android - PagingData 在 Paging 3 库中是否默认在后台线程上运行?
问题描述
后台线程是否PagingData
按原样自动管理PagedList
,然后在主线程上返回?
PagingData
从下面的日志中,与 Paging 2 的库相比,它似乎没有在 Paging 3 库的背景线程上运行PagedList
。
Expect(基于Paging Codelab示例)
- GithubPagingSource
override suspend fun load(...)
在 IO 线程上运行。 - SearchRepositoriesActivity
viewModel.searchRepo(query).collectLatest { ... }
在主线程上运行。
观察
- GithubPagingSource和SearchRepositoriesActivity都在主线程上运行。
override suspend fun load(...)
viewModel.searchRepo(query).collectLatest { ... }
分页 2
根据文档,线程由PagedList
with在后台处理。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
。但是,日志仍然显示PagingSource
在FeedPagingSource.kt的主线程上运行。
FeedViewModel.kt
repository.initFeed().onEach {
println("Thread: FeedViewModel ${Thread.currentThread().name}")
_feed.value = it
}.flowOn(Dispatchers.IO).launchIn(viewModelScope)
解决方案
即使我在视图模型中使用它,它也没有在 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)
}
}
}
推荐阅读
- php - 跳过数据库中存在的实体
- javascript - 为什么 nvm (for windows) 不工作,并且无论何时运行它都会给出错误消息?
- html - 如何处理邮件签名中的动态图像
- sql - 如何将 ISNULL() 函数与 join 一起使用
- c++ - 从另一个文件夹配置时,Automake 使用源的绝对路径
- python-3.x - 当在 ODOO 12 中创建模型 B 的新实例(模型 A 具有 many2one 字段)时,如何更改模型 A 中的布尔值?
- java - 如何让后台任务在地图上移动标记
- git - Visual Studio Code 和 git:X 的权限被拒绝
- tensorflow - 方向敏感图像数据的问题
- asp.net - ASP Core 3 上的 JWT + SignalR 导致 401 Unauthorized