Android Room Paging3 动态过滤的正确方法

Hec*_*tor 3 android android-room android-paging-3

我正在研究新的 Android Room Paging 库

   implementation "androidx.paging:paging-runtime-ktx:3.0.0-alpha09"
Run Code Online (Sandbox Code Playgroud)

我的源数据库表大约有 10,000 行,我按名称字段的第一个字符进行过滤,如下所示:-

@Query("SELECT * from citation_style WHERE citation_style_name LIKE :startsWith ORDER BY citation_style_name ASC")
fun fetch(startsWith: String): PagingSource<Int, CitationStyleDO>
Run Code Online (Sandbox Code Playgroud)

存储库

fun fetch(startsWith: String): Flow<PagingData<CitationStyleDO>> {
    return Pager(
        PagingConfig(pageSize = 60, prefetchDistance = 30, enablePlaceholders = false, maxSize = 200)
    ) { database.citationStyleDao().fetch("$startsWith%") }.flow
}
Run Code Online (Sandbox Code Playgroud)

视图模型

fun fetch(startsWith: String): Flow<PagingData<CitationStyleDO>> {
    return repository.fetch(startsWith).cachedIn(viewModelScope)
}
Run Code Online (Sandbox Code Playgroud)

分段

override fun onStartsWithClicked(startsWith: String) {
    lifecycleScope.launch {
        viewModel.fetch(startsWith).collectLatest { adapter.submitData(it) }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是lifecycleScope.launch {...}每次更改开始字符时重复使用的正确方法吗?

我应该是map{}还是switchMap{}MutabaleLiveData<String>for StartwWith触发?

dla*_*lam 5

这是行不通的,因为 submitData 在PagingData失效之前不会返回。您可能会遇到竞争场景,其中启动了多个作业,PagingDataAdapter试图从多个PagingData.

更“流”的方法是将您的 fetch 调用转换为流并将其与您的 结合Flow<PagingData>,这将在每次查询更改时自动传播取消。

其他几件事:

建议让 Paging 为您进行过滤,这样您就可以避免每次搜索更改时从数据库重新获取,并且您还可以依靠 Paging 来处理配置更改和恢复状态。

您应该使用viewLifecycleOwner而不是lifecycleScope直接使用,因为您不希望在片段视图被销毁后进行分页

例如,

视图模型

val queryFlow = MutableStateFlow("init_query")
val pagingDataFlow = Pager(...) {
        dao.pagingSource()
    }.flow
    // This multicasts, to prevent combine from refetching
    .cachedIn(viewModelScope)
    .combine(queryFlow) { pagingData, query -> 
        pagingData.filter { it.startsWith(query)
    }
    // Optionally call .cachedIn() here a second time to cache the filtered results. 
Run Code Online (Sandbox Code Playgroud)

分段

override fun onStartsWithClicked(startsWith: String) {
    viewModel.queryFlow = startsWith
}

override fun onViewCreated(...) {
     viewLifecycleOwner.lifecycleScope.launch {
viewModel.pagingDataFlow.collectLatest { adapter.submitData(it) }
}
Run Code Online (Sandbox Code Playgroud)

注意:如果需要,您绝对可以使用 Room 进行过滤,这可能是查询流.flatMapLatest上的正确方法并返回一个新的Pager每个 tine,并将查询词传递给返回一个的 dao 函数PagingSource

视图模型

queryFlow.flatMapLatest { query ->
    Pager(...) { dao.pagingSource(query) }
        .cachedIn(...)
}
Run Code Online (Sandbox Code Playgroud)