微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Room 的分页无法将 Flow<PagingData<Model>> 与其他流正确合并

如何解决Room 的分页无法将 Flow<PagingData<Model>> 与其他流正确合并

我正在尝试使用 Paging 3 库从 Flow<PagingData<Scan>> 获取 Room,然后检查是否在 recyclerview 中选择了项目,因此我将此类映射到另一个类称为 ScanMapper。为了实现这种映射,每当用户一个项目标记为选中时,我都会在 Map 中更新 MutableStateFlow<Map<Int,State>>。这里 Map 查找 Index(Int) 以获得 StateState 只是一个 enum 类来表示状态 UNINITIALISED,{{1 }} 和 USELECTED

我将 Map 的值设置为 SELECTED。问题是,我试图将 StateFlow<Map<Int,State>>Flow<PagingData<Scan>> 结合起来,以便将 StateFlow<Map<Int,State>> 作为参数传递给 State 类,因为这个 {{1} } 取自 ScanMapper 并且不是原始 State 类的一部分。但是 StateFlow<Map<Int,State>> 似乎总是得到 Scan,尽管我使用 PagingDataAdapter 函数在项目点击时将项目标记为已选中。

请告诉我我在这里遗漏了什么。

更新

通过使用 State UNINITIALISED 并使用带有 markSelected(scanId: Int) 的回收器适配器移除 Flow<List<Scan>> 库的使用,我能够实现我想要的功能。虽然这不是实际的解决方案,因为它消除了 Paging 3 库,但以下更改允许我执行项目选择:

更新道

DiffUtils

viewmodel 中的更新函数

pagination using paging 3

更新片段代码

@Query("SELECT * FROM scan ORDER BY timeOfStorage DESC")
fun getAllScansList(): Flow<List<Scan>>

原始问题

我的扫描课程:

fun getData(context: Context): Flow<List<ScanMapper>> {

    val dao = ScanDatabase.invoke(context).getScanDao()

    return combine(
        dao.getAllScansList(),myMap
    ) { scan,stateMap ->
        scan.map {
            it.toScanMapper(stateMap[it.id] ?: State.UNKNowN)
        }
    }.flatMapLatest {
        flow {
            emit(it)
        }
    }
}

我的 ScanMapper 类:

mainviewmodel.getData(requireContext()).collect {

    adapter.asyncListDiffer.submitList(it as MutableList)
}

将扫描转换为 ScanMapper,反之亦然

@Entity(tableName = "scan")
@Parcelize
data class Scan (
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,val name: String,val recognisedText: String,val timeOfStorage: Long,val filename: String
): Parcelable {

}

我在 Dao 中的 PagingSource

data class ScanMapper(
    val id: Int,val filename: String,val isSelected: State
)

enum class State{
    UNINITIALISED,SELECTED,UNSELECTED,UNKNowN
}

使用 getScansFlow() 获取流量

fun ScanMapper.mapToScan() =
Scan(
    id = id,name = name,recognisedText = recognisedText,timeOfStorage = timeOfStorage,filename = filename
)

fun Scan.toScanMapper(isSelected: State) =
ScanMapper(
    id = id,filename = filename,isSelected = isSelected
)

为 Room 中存在的 id 初始化 Map

@Query("SELECT * FROM scan ORDER BY timeOfStorage DESC")
fun getAllScans(): PagingSource<Int,Scan>

@Query("SELECT id FROM scan")
fun getAllIds(): List<Int>

viewmodel 中获取流并将它们组合起来的函数

fun getScansFlow(context: Context): Flow<PagingData<Scan>> {

    val scanDao = ScanDatabase.invoke(context).getScanDao()

    return Pager(
        config = PagingConfig(
            pageSize = 10,maxSize = 30,enablePlaceholders = false
        ),pagingSourceFactory = { scanDao.getAllScans() }
    ).flow.cachedIn(viewmodelScope)

}

fun initList() = viewmodelScope.launch { var idList: List<Int> = listof() withContext(dispatchers.IO) { val task = async { return@async ScanDatabase.invoke(context).getScanDao().getAllIds() } idList = task.await() } val map = _myMap.value.toMutableMap() for (id in idList) { map[id] = State.UNINITIALISED } _myMap.value = map } 一个 fun getScansSyncFlow(context: Context) { viewmodelScope.launch { combine( getScansFlow(context),myMap ) { scan,stateMap -> scan.map { it.toScanMapper(stateMap[it.id] ?: State.UNKNowN) } }.collect{ _myFlow.emit(it) } } }

这就是当用户在 recyclerview 中选择项目时更新 myFlow 的方式。

StateFlow<PagingData<ScanMapper>?>

然后,我像这样在我的 Map 中收集这个 fun markSelected(scanId: Int) { val map = _myMap.value.toMutableMap() map[scanId] = State.SELECTED _myMap.value = map }

myFlow

解决方法

我看到的直接问题是您使用的是 collect 而不是 collectLatest。由于 submitData 不会返回,您将永远不会收到来自 Flow 的更新。

mainViewModel.myFlow.collectLatest {
  adapter.submitData(it)
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。