首页 > 解决方案 > PagingData 在 Paging 3 库中是否默认在后台线程上运行?

问题描述

后台线程是否PagingData按原样自动管理PagedList,然后在主线程上返回?

PagingData从下面的日志中,与 Paging 2 的库相比,它似乎没有在 Paging 3 库的背景线程上运行PagedList

Expect基于Paging Codelab示例

观察

分页 2

根据文档,线程由PagedListwith在后台处理。toLiveData

如果您使用 LivePagedListBuilder 获取 LiveData,它将在后台线程上为您初始化 PagedLists。

第 3 页

Paging 3文档没有提到如何管理线程。但是,从日志来看,PagingSource似乎是在主线程上运行网络请求并在主线程上返回PagingData

我的示例代码

我在CryptoTweets示例应用app-simple模块中重新创建了 Codelab 模式。

FeedPagingSource.kt

class FeedPagingSource : PagingSource<Int, Tweet>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Tweet> {
        try {
            val page = params.key ?: 1
            val nextPage = page + 1
            val tweets = Injection.feedService.getTweets(...)
            println("Thread: FeedPagingSource ${Thread.currentThread().name}")
            Log.v(LOG_TAG, "load success: ${tweets}")
            return LoadResult.Page(...)
        } catch (error: Exception) {
            ...
        }
    }
}

FeedRepository.kt

class FeedRepository {
    fun initFeed() = Pager(
        config = PagingConfig(pageSize = FEED_PAGEDLIST_SIZE),
        pagingSourceFactory = { FeedPagingSource() }
    ).flow
}

FeedViewModel.kt

repository.initFeed().onEach {
    println("Thread: FeedViewModel ${Thread.currentThread().name}")
    _feed.value = it
}.launchIn(viewModelScope)

尝试的解决方案

为了PagingSource在后台线程上运行,流程在 上启动Dispatchers.IO。但是,日志仍然显示PagingSourceFeedPagingSource.kt的主线程上运行。

FeedViewModel.kt

repository.initFeed().onEach {
            println("Thread: FeedViewModel ${Thread.currentThread().name}")
            _feed.value = it
}.flowOn(Dispatchers.IO).launchIn(viewModelScope)

标签: androidkotlinandroid-jetpackandroid-pagingandroid-thread

解决方案


即使我在视图模型中使用它,它也没有在 Paging 3 的后台线程上运行lifecycleScope.launch(Dispatchers.IO),因为在适配器加载时从主线程访问 PagingSource。所以对于 Room,我通过将 PagingSource 数据库代码包装在里面来让它工作withContext(Dispatchers.IO) {

private const val STARTING_PAGE_INDEX = 0
private const val COUNT_PER_PAGE = 20

class LocalImagesPagingSource() : PagingSource<Int, GalleryImage>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, GalleryImage> {
        val page = params.key ?: STARTING_PAGE_INDEX
        return try {
            withContext(Dispatchers.IO) {
                val dao = GalleryImageDatabase.getDatabase(context).galleryImageDao()
                val images = dao.getGalleryImagesByPosition(page * COUNT_PER_PAGE)

                LoadResult.Page(
                    data = images,
                    prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1,
                    nextKey = if (images.size == 0) null else page + 1
                )
            }
        } catch (exception: IOException) {
            return LoadResult.Error(exception)
        }
    }
}

推荐阅读