第 3 页初始加载未显示
Posted
技术标签:
【中文标题】第 3 页初始加载未显示【英文标题】:Paging 3 initial loading not shown 【发布时间】:2020-12-04 16:40:07 【问题描述】:我正在处理第 3 页,除了初始加载状态外,一切正常。我正在添加withLoadStateFooter
,但它在第一次调用时从不显示加载状态
这是我的实现
负载状态适配器
class LoadStateAdapter (
private val retry: () -> Unit
): LoadStateAdapter<LoadStateViewHolder>()
override fun onBindViewHolder(holder: LoadStateViewHolder, loadState: LoadState)
holder.bindTo(loadState)
override fun onCreateViewHolder(
parent: ViewGroup,
loadState: LoadState
): LoadStateViewHolder
return LoadStateViewHolder.create(parent, retry)
加载状态视图支架
class LoadStateViewHolder(
view : View,
private val retryCallback: () -> Unit
) : RecyclerView.ViewHolder(view)
private val progressBar = view.findViewById<ProgressBar>(R.id.progress_bar)
private val errorMsg = view.findViewById<TextView>(R.id.error_msg)
private val btnRetry = view.findViewById<Button>(R.id.retry_button)
.also
it.setOnClickListener retryCallback()
private var loadState : LoadState? = null
companion object
fun create(parent: ViewGroup, retryCallback: () -> Unit): LoadStateViewHolder
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.network_state_item, parent, false)
return LoadStateViewHolder(
view,
retryCallback
)
fun bindTo(loadState: LoadState)
this.loadState = loadState
btnRetry.isVisible = loadState !is LoadState.Loading
errorMsg.isVisible = loadState !is LoadState.Loading
progressBar.isVisible = loadState is LoadState.Loading
if (loadState is LoadState.Error)
errorMsg.text = loadState.error.localizedMessage
寻呼源
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Model>
try
// Load page 1 if undefined.
val currentPage = params.key ?: 0
val offset = currentPage * 50
val requestParams = hashMapOf<String, Any>()
requestParams.put("limit", 50)
requestParams.put("offset", offset)
val response = repository.getList(requestParams)
val isFinish = response.paging != null && response.paging!!.next == null
return LoadResult.Page(
data = response.data ?: mutableListOf(),
prevKey = null, // Only paging forward.
nextKey = if (isFinish) null else currentPage + 1
)
catch (e: Exception)
// Handle errors in this block
return LoadResult.Error(e)
查看模型
val listPagingFlow = Pager(PagingConfig(pageSize = 50))
MyPagingSource(repository)
.flow.cachedIn(viewModelScope)
活动
val pagingAdapter = MyPagingAdapter()
list.apply
setHasFixedSize(true)
adapter = pagingAdapter.withLoadStateFooter(
footer = LoadStateAdapter pagingAdapter.retry()
)
lifecycleScope.launch(Dispatchers.IO)
viewModel.listPagingFlow.collectLatest pagingData ->
pagingAdapter.submitData(pagingData)
MyPagingAdapter 很简单 PagingDataAdapter
简而言之;加载状态工作正常,但在第一次请求时没有显示。有人可以帮忙吗?
当前版本3.0.0-alpha04
【问题讨论】:
【参考方案1】:withLoadStateFooter
返回一个ConcatAdapter
,它将原始PagingDataAdapter
的结果与一个侦听CombinedLoadState.append
事件的LoadStateAdapter
连接起来。因此,它不会在初始加载期间返回项目 (loadType == REFRESH
),并且它是这样设计的,因为在任何项目加载之前显示“页脚”实际上没有任何意义。
但是,要实现您想要的,您可以简单地创建自己的 ConcatAdapter,它非常接近地反映了 .withLoadStateFooter
的实现:
val originalAdapter = MyPagingDataAdapter(...)
val footerLoadStateAdapter = MyFooterLoadStateAdapter(...)
addLoadStateListener loadStates ->
// You need to implement some logic here to update LoadStateAdapter.loadState
// based on however you want to prioritize between REFRESH / APPEND load states.
// Something really basic might be:
// footerLoadStateAdapter.loadState = when
// loadStates.refresh is NotLoading -> loadStates.append
// else -> loadStates.refresh
//
footerLoadStateAdapter.loadState = ...
return ConcatAdapter(originalAdapter, footerLoadStateAdapter)
【讨论】:
我不明白答案。你能给我一些参考资料或链接吗? 我也没有,我遇到了类似的问题,但无法理解正确的解决方案,有什么帮助吗? 如何澄清上面的示例代码?ConcatAdapter
将来自多个适配器的数据合并为一个,让您可以在 RecyclerView
中显示来自多个适配器的数据。 LoadStateAdapter
是 Paging 库中的一个内置项,它根据 displayLoadStateAsItem
返回的内容显示 0 或 1 个项目,您可以通过公共可变属性设置状态。见developer.android.com/reference/kotlin/androidx/paging/…
此示例展示了如何自定义 LoadStateAdapter 的默认行为的示例,因此您可以选择何时切换到另一个 LoadState。有些人可能会对来自不同 LoadType 的 LoadState 的组合感兴趣,具体取决于他们的用例。【参考方案2】:
使用页脚LoadStateAdapter
显示初始加载会导致问题。如 cmets 中所述,列表将自动滚动到底部。
解决这个问题的方法是使用两个LoadStateAdapter
s,一个显示初始加载,第二个显示加载更多项目时的加载。
fun <T : Any, V : RecyclerView.ViewHolder> PagingDataAdapter<T, V>.withLoadStateAdapters(
header: LoadStateAdapter<*>,
footer: LoadStateAdapter<*>
): ConcatAdapter
addLoadStateListener loadStates ->
header.loadState = loadStates.refresh
footer.loadState = loadStates.append
return ConcatAdapter(header, this, footer)
【讨论】:
【参考方案3】:我建议将初始加载和空状态从分页适配器中取出,并这样做:
adapter.loadStateFlow.collect
// to determine if we are done with the loading state,
// you should have already shown your loading view elsewhere when the entering your fragment
if (it.prepend is LoadState.NotLoading && it.prepend.endOfPaginationReached)
loading.visibility = View.GONE
if (it.append is LoadState.NotLoading && it.append.endOfPaginationReached)
emptyState.isVisible = adapter.itemCount < 1
逻辑是
如果追加已完成(it.append 为 LoadState.NotLoading && it.append.endOfPaginationReached == true),并且我们的适配器项目计数为零(adapter.itemCount ),表示没有什么可显示的,所以我们显示空状态 如果 prepend 已经完成(it.prepend 是 LoadState.NotLoading && it.prepend .endOfPaginationReached == true),那么我们已经完成了初始加载视图,我们应该隐藏它【讨论】:
【参考方案4】:作为@dlam 的回答,您可以在适配器中使用自定义 ConcatAdapter 而不是 withLoadStateFooter
fun withMySpecificFooter(
footer: LoadStateAdapter<*>
): ConcatAdapter
addLoadStateListener loadStates ->
footer.loadState = when (loadStates.refresh)
is LoadState.NotLoading -> loadStates.append
else -> loadStates.refresh
return ConcatAdapter(this, footer)
【讨论】:
它正在工作,但为什么列出从中间显示的项目?即如果我有 10 个项目,recyclerview 显示第 5 个初始项目,必须滚动到顶部才能看到第一个项目。 @HadiAhmadi 同样的问题 每当使用 withLoadStateFooter() 时,我都遇到了从中间开始的 RecyclerView 的相同问题。有谁知道如何解决这个问题?提前致谢。以上是关于第 3 页初始加载未显示的主要内容,如果未能解决你的问题,请参考以下文章
淘汰赛 JS 选择初始值在 foreach 循环内未正确显示
Sencha Touch 2.2.1 Carousel 未初始化