【问题标题】:Android Jetpack Paging 3: PagingSource with RoomAndroid Jetpack Paging 3:带 Room 的 PagingSource
【发布时间】:2020-12-12 19:46:04
【问题描述】:

我正在使用最新的 Jetpack 库。
分页3版本:3.0.0-alpha05
房间版:2.3.0-alpha02

我的实体有 Long as PrimaryKey 并且 Room 可以为 Int 以外的类型生成 PagingSource

error: For now, Room only supports PagingSource with Key of type Int.
    public abstract androidx.paging.PagingSource<java.lang.Long, com.example.myEntity>` getPagingSource();

因此我尝试实现我的自定义PagingSource,例如docs 建议。

问题是数据刷新,因为 Room 生成的代码处理数据刷新,而我的代码无法处理这种情况。

任何建议如何为Room 实现自定义PagingSource,同时处理Data Refresh

【问题讨论】:

    标签: android android-room android-paging android-paging-library android-paging-3


    【解决方案1】:

    由于您有“刷新”场景并使用 Room db,我猜您正在使用 Paging3 和网络+本地 db 模式(使用 Room db 作为本地缓存)。

    我在网络 + 本地数据库模式下也遇到过类似的情况。我不确定我是否正确理解了您的问题,或者您的情况与我的情况相同,但我还是会分享我所做的。

    我使用的是什么:

    • 分页3:3.0.0-beta01
    • 房间:2.3.0-beta02

    我所做的是让 Room 库创建 PagingSource(使用 Int 的键),并让 RemoteMediator 处理所有其他情况,例如在刷新和/或追加时从网络获取数据,以及插入获取成功后它们立即进入数据库。

    我的dao 函数用于从房间库创建 PagingSource:

    @Query("SELECT * FROM article WHERE isUnread = 1")
    fun getUnreadPagingSource(): PagingSource<Int, LocalArticle>
    

    在我的例子中,我将 Repository 类定义为在其构造函数中包含 dao 类,以便在创建 Pager 类时从存储库中调用上述函数。

    我的自定义 RemoteMediator 类如下所示:

    • 注意:在我的例子中,没有 PREPEND 情况,所以当参数 loadType 的值为 LoadType.PREPEND 时,RemoteMediator#load 函数总是返回 true
    class FeedMediator(
        private val repository: FeedRepository
    ) : RemoteMediator<Int, LocalArticle>() {
    
        ... 
    
        override suspend fun load(
            loadType: LoadType,
            state: PagingState<Int, LocalArticle>
        ): MediatorResult = runCatching {
            when (loadType) {
                LoadType.PREPEND -> true
                LoadType.REFRESH -> {
                    feedRepository.refresh()
                    false
                }
                LoadType.APPEND -> {
                    val continuation = feedRepository.continuation()
                    if (continuation.isNullOrEmpty()) {
                        true
                    } else {
                        loadFeedAndCheckContinuation(continuation)
                    }
                }
            }
        }.fold(
            onSuccess = { endOfPaginationReached -> MediatorResult.Success(endOfPaginationReached) },
            onFailure = {
                Timber.e(it)
                MediatorResult.Error(it)
            }
        )
    
        private suspend fun loadFeedAndCheckContinuation(continuation: String?): Boolean {
            val feed = feedRepository.load(continuation)
            feedRepository.insert(feed)
            return feed.continuation.isNullOrEmpty()
        }
    

    终于可以创建Pager类了。

    fun createFeedPager(
            mediator: FeedMediator<Int, LocalArticle>,
            repository: FeedRepository
        ) = Pager(
            config = PagingConfig(
                pageSize = FETCH_FEED_COUNT,
                enablePlaceholders = false,
                prefetchDistance = PREFETCH_DISTANCE
            ),
            remoteMediator = mediator,
            pagingSourceFactory = { repository.getUnreadPagingSource() }
        )
    

    我希望它在某种程度上有所帮助..

    其他参考资料:


    编辑: 再次阅读文档后,我发现the doc明确指出:

    RemoteMediator 用于将数据从网络加载到本地数据库。

    【讨论】:

    • 您好,感谢您的回复!我记得我没有网络要求,但我需要支持Long 主键,不幸的是Paging3 PagingSource 不支持。我最终为Int 创建了额外的行,为Long 创建了另一行。这样PagingSource 仍然可以使用Int 键。
    • 没有回答这个问题,因为答案没有提到如何实现自定义 PagingSource 或如何使用分页 3 库和 Room 将非整数作为 PrimaryKey 处理。
    猜你喜欢
    • 2023-01-18
    • 2021-11-06
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    相关资源
    最近更新 更多