未显示分页 3 初始加载



我正在使用分页 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

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)

使用页脚LoadStateAdapter显示初始加载将导致问题。该列表将自动滚动到底部,如评论中所述。

解决此问题的方法是使用两个LoadStateAdapter,一个用于显示初始加载,另一个用于显示加载更多项目时的加载。

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)
}

我建议将初始加载和空状态从分页适配器中提升出来,并像这样操作:

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.endOfPaginationReach == true),并且我们的适配器项目计数为零(adapter.itemCount <1),则意味着没有什么可显示的,所以我们显示空状态
  • 如果 prepend 已经完成(it.prepend是 LoadState.NotLoading && it.prepend .endOfPaginationReach == true),那么我们已经完成了初始加载视图,我们应该隐藏它

作为@dlam答案,您可以在适配器中使用自定义 ConcatAdapter 而不是 LoadStateFooter

fun withMySpecificFooter(
footer: LoadStateAdapter<*>
): ConcatAdapter {
addLoadStateListener { loadStates ->
footer.loadState = when (loadStates.refresh) {
is LoadState.NotLoading -> loadStates.append
else -> loadStates.refresh
}
}
return ConcatAdapter(this, footer)
}

最新更新