【问题标题】:How to show empty view while using Android Paging 3 library使用 Android Paging 3 库时如何显示空视图
【发布时间】:2020-10-15 11:36:26
【问题描述】:

我正在使用 Paging 3 库。我可以检查刷新状态是“加载”还是“错误”,但我不确定如何检查“空”状态。我可以添加以下条件,但我不确定它是否正确

adapter.loadStateFlow.collectLatest { loadStates ->
                viewBinding.sflLoadingView.setVisibility(loadStates.refresh is LoadState.Loading)
                viewBinding.llErrorView.setVisibility(loadStates.refresh is LoadState.Error)
                viewBinding.button.setOnClickListener { pagingAdapter.refresh() }

                if(loadStates.refresh is LoadState.NotLoading && (viewBinding.recyclerView.adapter as ConcatAdapter).itemCount == 0){
                    viewBinding.llEmptyView.setVisibility(true)
                }else{
                    viewBinding.llEmptyView.setVisibility(false)
                }
            } 

我也遇到了其他问题 我已经实现了搜索功能,并且在输入超过 2 个字符之前,我使用的是相同的分页源,如下所示,但上面的 loadstate 回调只执行一次。这就是为什么如果清除搜索查询,我无法隐藏空视图。我是这样做是为了节省前端的 api 调用。

private val originalList : LiveData<PagingData<ModelResponse>> = Transformations.switchMap(liveData){
        repository.fetchSearchResults("").cachedIn(viewModelScope)
    }

    val list : LiveData<LiveData<PagingData<ModelResponse>>> = Transformations.switchMap{ query ->
        if(query != null) {
            if (query.length >= 2)
                repository.fetchSearchResults(query)
            else
                originalList
        }else
            liveData { emptyList<ModelResponse>() }
    } 

【问题讨论】:

  • repository.fetchSearchResults(query) 的实现是什么样的,何时调用 submitData?你如何验证回调只被调用一次?您应该在任何状态更改(包括附加/前置)时收到一个新的 CombinedLoadStates。需要明确的是,您的条件检查 ConcatAdapter 的 itemCount,但我认为您只需要 PagingDataAdapter 的 itemCount,因为 ConcatAdapter 还将包括其他适配器(例如 LoadStateAdapter)。仅供参考:您可以使用submitData(PagingData.empty()) 清除列表。
  • fun fetchSearchResults(searchQuery : String): LiveData&lt;PagingData&lt;ModelResponse&gt;&gt; { return Pager( config = PagingConfig(pageSize = DEFAULT_PAGE_SIZE, enablePlaceholders = false), pagingSourceFactory = { ModelPagingSource(searchQuery) } ).liveData }
  • @dlam 关于回调问题,在正常情况下它工作正常。如果查询长度小于 2,我正在尝试重用相同的分页源(originalList),并且在重用相同的 obj(originalList)之后,不执行 loadstate 回调方法,我认为这是对于一个分页源的预期行为,刷新 loadstate 将是仅在达到“错误”或“未加载”状态之前调用,并且在我们进行一些显式调用之前不会再次调用
  • 你能解释一下如何检查列表中的空状态
  • 你说得对,重复使用PagingSource 会导致问题。我会尝试过滤搜索输入,以便在您不想重新加载时不会最终重新加载,而不是尝试“重用”PagingSource。为了检查空状态,PagingDataAdapter.itemCount 将在从 loadStateFlow / 侦听器调用时起作用(加载状态事件保证与插入事件同步发送,因此您可以确定已加载的页面已呈现)。还有一个.snapshot() 方法,以防您需要查看自己呈现的实际项目。

标签: android


【解决方案1】:

这是在 Android Paging 3 中处理空视图的正确方法:

adapter.addLoadStateListener { loadState ->
            if (loadState.source.refresh is LoadState.NotLoading && loadState.append.endOfPaginationReached && adapter.itemCount < 1) {
                recycleView?.isVisible = false
                emptyView?.isVisible = true
            } else {
                recycleView?.isVisible = true
                emptyView?.isVisible = false
            }
        }

【讨论】:

  • 如果还有几页要抓取怎么办?对于那个 endOfPaginationReached 将返回 false,这将导致 emptyView 被显示,即使数据在那里。如果我错了,请纠正我。
  • 总是返回 endOfPaginationReached "false"
  • 对我来说loadState.source.refresh is LoadState.NotLoading &amp;&amp; loadState.append.endOfPaginationReached 似乎已经足够了
  • @Gulzar Bhat,显示初始加载程序的逻辑是什么?我的意思是,在第一次网络调用时显示 Lottie 动画?
  • 为什么我必须检查零作为adapter.itemCount &lt; 1?我认为可以与adapter.itemCount == 0 核对。有什么区别吗?
【解决方案2】:

我正在使用这种方式,它可以工作。

编辑: dataRefreshFlow 在版本 3.0.0-alpha10 中已弃用,我们现在应该使用 loadStateFlow

  viewLifecycleOwner.lifecycleScope.launch {
            transactionAdapter.loadStateFlow
                .collectLatest {
                    if(it.refresh is LoadState.NotLoading){
                        binding.textNoTransaction.isVisible = transactionAdapter.itemCount<1
                    }
                }
        }

loadStateFlow的详细解释和用法请查看 https://developer.android.com/topic/libraries/architecture/paging/v3-paged-data#load-state-listener

【讨论】:

    【解决方案3】:
    adapter.loadStateFlow.collect {
        if (it.append is LoadState.NotLoading && it.append.endOfPaginationReached) {
            emptyState.isVisible = adapter.itemCount < 1
        }
    }
    

    逻辑是,如果追加完成(it.append is LoadState.NotLoading && it.append.endOfPaginationReached == true),并且我们的适配器项计数为零(适配器.itemCount ),表示没有东西可以显示,所以我们显示空状态。

    PS:对于初始加载,您可以在此答案中找到更多信息:https://stackoverflow.com/a/67661269/2472350

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-28
      相关资源
      最近更新 更多