更新当前页面或更新 Paging 3 library Android Kotlin 中的数据

10

我在使用Android Kotlin中的Paging 3库时比较新手。我想要无限获取数据。所以我发现Paging 3库在我的情况下非常有用。我使用PagingSource创建了一个列表,但是我没有使用Room,并且我有一个嵌套的RecyclerView。我使用了带有DiffUtilPagingDataAdapter来为我的RecyclerView提供数据。我使用了从Codelab推荐的Paging library教程,没有遇到任何问题。然而,我现在遇到了更新项目的困难。我使用了分页源来创建列表,并且里面含有一些来自服务器的数据,这一切都没有遇到任何问题。但是如何更新适配器或者通知RecyclerView数据已经改变呢?我已经设计了获取更新列表的机制。我在某些地方搜索了如何更新适配器,但每个地方都提到要使用DataSource中的invalidate()。在Paging 2中才有DataSource吧?现在根据文档,在升级到Paging 3中加入了。Flow被用于检索数据。这段代码在ViewModel类中。

fun createRepo(data: List<String>, repository: RepositoryData): Flow<PagingData<UnlimitData>> {
    return repository.getStreamData(data).cachedIn(viewModelScope)
}

我正在传递一份来自服务器的列表。 getStreamData 函数返回包含整数和字符串数据的项目。我的 Data 类

data class UnlimitData(val id: Int, val name: String)

createRepo 在我的 Activity 类中被调用,以便将数据发送到适配器。

lifecycleScope.launch {
        viewModel.createRepo(serverData,repository).collectLatest { data ->
            adapter.submitData(data)
        }
}

这是我的适配器代码:

class unlimitedAdapter() :
    PagingDataAdapter<UnlimitData, RecyclerView.ViewHolder>(COMPARATOR) {

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val item = getItem(position)
    if (item != null) {
        (holder as UnlimitedViewHolder).bind(item)
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return UnlimitedViewHolder.create(parent)
}

companion object {
    private val COMPARATOR = object : DiffUtil.ItemCallback<UnlimitData>() {
        override fun areItemsTheSame(oldItem: UnlimitData, newItem: UnlimitData): Boolean =
            oldItem.id == newItem.id

        override fun areContentsTheSame(oldItem: UnlimitData, newItem: UnlimitData): Boolean = oldItem == newItem
    }
}

我添加了逻辑来使用RetroFit插入/更新列表中的数据。我的列表已经成功更新,但我无法刷新reyclerview。

提前感谢。

3个回答

4
为了让分页拾取新项目,您需要调用PagingSource.invalidate()来通知Pager需要获取新的PagingSource并重新加载页面。 您需要跟踪工厂生成的所有PagingSource,并在每次从网络更新后端数据集时使其无效化。
abstract class InvalidatingPagingSourceFactory<K,V> : () -> PagingSource<K,V> {
    private val list = mutableListOf()

    abstract fun create()

    override final fun invoke() {
        create().also { list.add(it) }
    }

    fun invalidate() {
        while (list.isNotEmpty()) { list.removeFirst().invalidate() }
    }
}

1
@dlam 目前我的 ViewModel 只能访问 Pagerflow(),它返回一个 Flow<PagingData<Value>>,所以在那个时候访问 Pager 已经丢失了。这是否意味着我必须在 ViewModel 中保存 Pager 才能使用它?这并不是很方便,因为为了实现这一点,之前对数据源不可知的 ViewModel 现在需要为每个数据源(本地和远程)保存一个 Pager。你有一个具体的示例项目来说明如何使用 InvalidatingPagingSourceFactory 吗? - J. Doe
你不需要在Pager之间传递,只需要在Pager中传递InvalidatingPagingSourceFactory并保留对InvalidatingPagingSourceFactory的引用即可。你想要做的是将InvalidatingPagingSourceFactory.invalidate()连接到你的数据源。这取决于你打算如何监听它。你的Pager定义在哪一层,你期望外部失效信号来自哪里? - dlam
无论在何处声明 Pager,您都应该能够访问存储库层,因为您需要给 Pager 存储库抽象 PagingSource,这也应该提供对用于触发失效的外部信号的访问。 - dlam
3
@dlam,你能否给我们一个invalidate如何工作的实际例子呢?说实话,对于初学者来说,从库中学习和阅读是非常困难的。谢谢。 - Kotlin Learner
PagingSource有一个名为invalidate的方法。调用此方法会在Pager类中调用pagingSourceFactory lambda函数,从而创建一个反映源数据新数据的PagingSource实例。在编程上,PagingSource抽象类具有InvalidateCallbackTracker实例,该实例处理此无效操作。更多信息请参见:https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:paging/paging-common/src/main/kotlin/androidx/paging/PagingSource.kt?q=file:androidx%2Fpaging%2FPagingSource.kt%20class:androidx.paging.PagingSource - Nandha Kumar
显示剩余7条评论

0

当我们使用adapter.refresh()方法时,它会刷新最新的数据并与布局绑定。

但是它不会重新加载带有位置的recycler视图。 在这种情况下,您将得到错误的位置。

因为在DiffUtils中,您匹配正确。因此,每当您刷新时,它只会绑定那些新的未绑定数据。

所以,解决方案是您必须使DiffUtils为false。在这种情况下,PageSource将更新完整列表,并更新位置。

例如:oldItem.id ==-1

 private val COMPARATOR = object : DiffUtil.ItemCallback<UnlimitData>() {
        override fun areItemsTheSame(oldItem: UnlimitData, newItem: UnlimitData): Boolean =
            oldItem.id ==-1

        override fun areContentsTheSame(oldItem: UnlimitData, newItem: UnlimitData): Boolean = oldItem == newItem
    }

0
要使用invalidate()方法,我们需要将其包装在InvalidatingPagingSourceFactory中。
  private val pagingSourceInvalidatingFactory = InvalidatingPagingSourceFactory {
        PagingSource(
            repository = exampleRepository
        )
    }

val pager: Flow<PagingData<ExampleModel>> by lazy {
    Pager(
        config = PagingConfig(pageSize = PAGE_SIZE),
        pagingSourceFactory = pagingSourceInvalidatingFactory
    ).flow
}

然后你可以自由地在pagingSourceInvalidatingFactory上使用invalidate()函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接