mue*_*flo 3 android android-room android-jetpack android-paging android-paging-library
我正在为 Jetpack 的 Paging 3 Library 苦苦挣扎。
我设置
在PagingSource由空间中创建的。
我知道RemoteMediators 的职责是从网络中获取项目并将它们保存到 Room 数据库中。通过这样做,我们可以使用 Room 数据库作为单一事实点。PagingSource只要我使用整数作为 .Room就可以轻松地为我创建nextPageKeys.
到现在为止还挺好。这是我的 ViewModel 来检索以下列表Sources:
private lateinit var _sources: Flow<PagingData<Source>>
val sources: Flow<PagingData<Source>>
get() = _sources
private fun fetchSources() = viewModelScope.launch {
_sources = sourcesRepository.getSources(
selectedRepositoryUuid,
selectedRef,
selectedPath
)
}
Run Code Online (Sandbox Code Playgroud)
val sources收集在Fragment.
fetchSources()每当三个参数之一发生变化时调用 ( selectedRepositoryUuid, selectedRefor selectedPath)
这是 Paging 调用的存储库
fun getSources(repositoryUuid: String, refHash: String, path: String): Flow<PagingData<Source>> {
return Pager(
config = PagingConfig(50),
remoteMediator = SourcesRemoteMediator(repositoryUuid, refHash, path),
pagingSourceFactory = { sourcesDao.get(repositoryUuid, refHash, path) }
).flow
}
Run Code Online (Sandbox Code Playgroud)
现在我的经验是Repository.getSources首先使用正确的参数调用,RemoteMediator并且PagingSource创建了并且一切都很好。但是,一旦 3 个参数之一发生变化(比方说path),RemoteMediator 和 PagingSource 都不会重新创建。所有请求仍会尝试获取原始条目。
如果它有助于掌握我的用例: RecyclerView 正在显示文件和文件夹的分页列表。一旦用户点击一个文件夹,RecyclerView 的内容应该会改变以显示被点击文件夹的文件。
更新:
多亏了 dlam 的回答,代码现在是这样的。代码是真实代码的简化。我基本上把所有需要的信息都封装在了SourceDescription类中。:
视图模型:
private val sourceDescription = MutableStateFlow(SourceDescription())
fun getSources() = sourceDescription.flatMapConcat { sourceDescription ->
// This is called only once. I expected this to be called whenever `sourceDescription` emits a new value...?
val project = sourceDescription.project
val path = sourceDescription.path
Pager(
config = PagingConfig(30),
remoteMediator = SourcesRemoteMediator(project, path),
pagingSourceFactory = { sourcesDao.get(project, path) }
).flow.cachedIn(viewModelScope)
}
fun setProject(project: String) {
viewModelScope.launch {
val defaultPath = Database.getDefaultPath(project)
val newSourceDescription = SourceDescription(project, defaultPath)
sourceDescription.emit(newSourceDescription)
}
}
Run Code Online (Sandbox Code Playgroud)
在 UI 中,用户首先选择一个项目,该项目来自ProjectViewModelvia LiveData。一旦我们有了项目信息,我们就SourcesViewModel使用setProject上面的方法将其设置在 中。
分段:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// load the list of sources
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
sourcesViewModel.getSources().collectLatest { list ->
sourcesAdapter.submitData(list) // this is called only once in the beginning
}
}
projectsViewModel.projects.observe(viewLifecycleOwner, Observer { project ->
sourcesViewModel.setProject(project)
})
}
Run Code Online (Sandbox Code Playgroud)
Paging 的整体输出是 a Flow<PagingData>,因此通常通过一些流操作将您的信号(文件路径)混合到流中效果最佳。如果您能够将用户点击的路径建模为Flow<String>,那么这样的事情可能会起作用:
视图模型.kt
class MyViewModel extends .. {
val pathFlow = MutableStateFlow<String>("/")
val pagingDataFlow = pathFlow.flatMapLatest { path ->
Pager(
remoteMediator = MyRemoteMediator(path)
...
).flow.cachedIn(..)
}
}
Run Code Online (Sandbox Code Playgroud)
RemoteMediator.kt
class MyRemoteMediator extends RemoteMediator<..> {
override suspend fun load(..): .. {
// If path changed or simply on whenever loadType == REFRESH, clear db.
}
}
Run Code Online (Sandbox Code Playgroud)
如果您已加载所有内容,则另一种策略是将路径直接传递到 中PagingSource,但听起来您的数据来自网络,因此RemoteMediator这里的方法可能是最好的。
| 归档时间: |
|
| 查看次数: |
989 次 |
| 最近记录: |