Android Paging 3 在 invalidate() 上清除 recyclerview

Posted

技术标签:

【中文标题】Android Paging 3 在 invalidate() 上清除 recyclerview【英文标题】:Android Paging 3 clear recyclerview on invalidate() 【发布时间】:2021-11-05 07:32:11 【问题描述】:

我有一个可以应用过滤器的分页列表。用户应用过滤器后,recyclerview 应该在加载页脚中显示 0 个项目,直到它加载第一个项目并触发 LoadResul.Error 以防没有可显示的内容。

页脚工作正常,但您仍然可以看到调用 .invalidate() 之前存在的数据,并且您会看到该数据,直到它从后端获得新的响应(如果您的网络不好,这可能需要一些时间) .并且如果出现错误,旧项目仍然存在,并且会出现错误页脚。

关于如何实现这一点的任何想法?

我也在使用带有 RxJava 的库,所以这里是 DataSource 代码:


    override fun getRefreshKey(state: PagingState<Int, Event>): Int = 1

    override fun loadSingle(params: LoadParams<Int>): Single<LoadResult<Int, Event>> 
        val key = params.key ?: 1

        return repository.getCityEvents(
            cityId = globalData.currentCityId,
            start = selectedDates?.start?.toApiFormat(),
            end = selectedDates?.end?.toApiFormat(),
            pageNo = key,
            categories = categoryFilters
        )
            .map  it.content 
            .map  toLoadResult(it, params) 
            .onErrorReturn  LoadResult.Error(it) 
    

    private fun toLoadResult(data: List<Event>, params: LoadParams<Int>): LoadResult<Int, Event> 
        val currentKey = params.key ?: 1

        return if (data.isEmpty() && currentKey == 1)
            LoadResult.Error(NoEventsException())
        else
            LoadResult.Page(
                data = data,
                prevKey = null,
                nextKey = if (data.size < params.loadSize) null else currentKey + 1
            )
    

【问题讨论】:

【参考方案1】:

首先,您需要将LoadStateAdapter 添加到您的PagingDataAdapter,如下所示:

item_paging_loading.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:orientation="vertical"
    android:padding="12dp">

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_
        android:layout_
        android:layout_gravity="center_horizontal" />

    <TextView
        android:id="@+id/textError"
        style="@style/TextSmall"
        android:layout_gravity="center"
        android:gravity="center"
        android:visibility="gone"
        tools:text="Some Error Occurred"
        tools:visibility="visible" />

    <TextView
        android:id="@+id/buttonRetry"
        style="@style/TextMedium"
        android:layout_gravity="center"
        android:background="?selectableItemBackground"
        android:padding="@dimen/_5dp"
        android:text="@string/retry"
        android:textColor="@color/colorAccent" />
</androidx.appcompat.widget.LinearLayoutCompat>

PaginationLoadStateAdapter.kt

class PaginationLoadStateAdapter(
    val retry: () -> Unit
) : LoadStateAdapter<PaginationLoadStateAdapter.PassengersLoadStateViewHolder>() 

    inner class PassengersLoadStateViewHolder(
        private val binding: ItemPagingLoadingBinding,
        private val retry: () -> Unit
    ) : RecyclerView.ViewHolder(binding.root) 
        fun bind(loadState: LoadState) 
            if (loadState is LoadState.Error) 
                binding.textError.text = loadState.error.localizedMessage
            
            binding.progressbar.visible(loadState is LoadState.Loading)
            binding.buttonRetry.visible(loadState is LoadState.Error)
            binding.textError.visible(loadState is LoadState.Error)
            binding.buttonRetry.setOnClickListener 
                retry()
            
        
    

    override fun onBindViewHolder(
        holder: PassengersLoadStateViewHolder,
        loadState: LoadState
    ) 
        holder.bind(loadState)
    

    override fun onCreateViewHolder(
        parent: ViewGroup,
        loadState: LoadState
    ) = PassengersLoadStateViewHolder(
        ItemPagingLoadingBinding.inflate(
            LayoutInflater.from(parent.context), parent, false
        ),
        retry
    )

PagingDataAdapter添加页眉和页脚的扩展功能

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)

你需要像这样为你的 RV 设置页眉和页脚:

binding.list.adapter = pagingDataAdapter.withLoadStateAdapters(
                header = PaginationLoadStateAdapter  adapterSimpleOffers.retry() ,
                footer = PaginationLoadStateAdapter  adapterSimpleOffers.retry() 
            )

用户应用过滤器后,您可以提交空数据以显示 0 个项目,然后再次加载您的分页。

pagingDataAdapter.submitData(lifecycle, PagingData.empty())
loadData()//load your data

【讨论】:

嘿@BotiraliKozimov 你能帮我解决这个问题吗issue

以上是关于Android Paging 3 在 invalidate() 上清除 recyclerview的主要内容,如果未能解决你的问题,请参考以下文章

Android Paging 3 在 invalidate() 上清除 recyclerview

Android Paging 3:LoadType.APPEND 返回空远程键

使用 Paging 3 Android 从房间获取最新数据

Android Paging 3 不显示 Loadstate Adapter

使用 Jetpack Compose 无限加载 Android Paging 3 库而无需滚动

Android Jetpack Paging 3:带 Room 的 PagingSource