带有房间的分页无法将Flow<PagingData<Model>与其他流正确合并 [英] Pagination with Room not able to merge Flow<PagingData<Model>> with other flows properly

查看:34
本文介绍了带有房间的分页无法将Flow<PagingData<Model>与其他流正确合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我正在将映射的值设置为StateFlow<Map<Int,State>>。问题是,我试图将Flow<PagingData<Scan>>StateFlow<Map<Int,State>>组合在一起,以便也将State作为参数传递给ScanMapper类,因为这个State取自StateFlow<Map<Int,State>>,而不是原始Scan类的一部分。但PagingDataAdapter似乎总是得到State UNINITIALISED,尽管当我使用markSelected(scanId: Int)功能将项目标记为选中时。

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

更新

我能够通过使用Flow<List<Scan>>并使用DiffUtils的回收器适配器删除Paging 3库来实现我想要的功能。虽然这不是实际的解决方案,因为它删除了pagination using paging 3库,但以下更改允许我执行项目选择:

已更新DAO

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

已更新ViewModel中的函数

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)
        }
    }
}

已更新片段代码

mainViewModel.getData(requireContext()).collect {

    adapter.asyncListDiffer.submitList(it as MutableList)
}

原始问题

我的扫描课程:

@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 {

}

我的ScanMapper类:

data class ScanMapper(
    val id: Int,
    val name: String,
    val recognisedText: String,
    val timeOfStorage: Long,
    val filename: String,
    val isSelected: State
)

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

扫描到ScanMapper的转换器

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

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

我的DAO中的PagingSource

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

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

使用getScansFlow()获取流

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)

}

初始化聊天室中存在的ID的映射

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

}

获取流并将其组合的ViewModel函数

    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) 
        }
    }
  }

myFlowStateFlow<PagingData<ScanMapper>?>

当用户在Rececumerview中选择项目时,我就是这样更新Map的。

fun markSelected(scanId: Int) {

    val map = _myMap.value.toMutableMap()
    map[scanId] = State.SELECTED
    _myMap.value = map
}

然后,我在fragment中收集这个myFlow,如下所示:

lifecycleScope.launchWhenStarted {

mainViewModel.getScansSyncFlow(requireContext())

mainViewModel.myFlow.collect { data ->

      data?.let {
        
          adapter.submitData(it)
       }
    }
}

推荐答案

我看到的直接问题是您正在使用Collect,而不是CollectLatest。由于submitData不返回,您将永远不会收到来自流的更新。

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

这篇关于带有房间的分页无法将Flow&lt;PagingData&lt;Model&gt;与其他流正确合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆