Room 分页无法正确地将 Flow> 与其他流合并

2024-05-09

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

我将 Map 的值设置为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)功能。

请告诉我我在这里缺少什么。

UPDATE

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

更新了刀

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

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

myFlow is a StateFlow<PagingData<ScanMapper>?>.

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

fun markSelected(scanId: Int) {

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

那我就收集这个myFlow in my fragment像这样:

lifecycleScope.launchWhenStarted {

mainViewModel.getScansSyncFlow(requireContext())

mainViewModel.myFlow.collect { data ->

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

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

mainViewModel.myFlow.collectLatest {
  adapter.submitData(it)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Room 分页无法正确地将 Flow> 与其他流合并 的相关文章

随机推荐

  • 如何确保 std::map 是有序的?

    Using a std map
  • Boost Fusion 文章、示例、教程?

    您知道 boost fusion 库使用的任何好的资源 文章 示例吗 Boost Fusion 看起来非常有趣 我想我了解它的工作原理以及如何使用基础知识 但我正在寻找一些显示任何有趣的用法 实践的资源 例如文章或博客 除了 boost o
  • 通过 std::function 进行函子引用

    基本上 我希望有以下语义 include
  • 在 Bookdown 中呈现附录图号

    Bookdown 是一个很棒的软件包 我期待看到它如何发展 但现在我在渲染数字方面遇到了麻烦pdf document2附录中的数字时的格式 具体来说 当带有标题的图形位于附录中时 图形编号应采用 A 1 A 2 B 1 B 2 等形式 但图
  • 无法访问类“std::basic_ios<_Elem,_Traits>”中声明的私有成员

    此特定方法有问题 不知道如何解决 我收到的错误是上面的 错误 C2248 std basic ios basic ios 不能 访问类中声明的私有成员 std basic ios C Program Files Microsoft Visu
  • 如何在 Swift ios 中获取国家/地区列表?

    我已经看到了两个与我类似的问题 但这些问题的答案对我不起作用 我有一个旧项目 其中在一组方括号内手动输入了国家 地区列表 我可以轻松地在我的 pickerView 中使用它 但我想知道是否有更有效的方法来做到这一点 我将在 UIPicker
  • 如何删除 TFS 工作区映射?

    我在一个团队项目中的 tfs 中有一个项目 然后我们将该项目移动到另一个团队项目中的不同位置 我已将 Jenkins 配置为连接到团队项目并构建我的解决方案 但是当我更改设置以连接到新的 tfs 团队项目时 出现以下错误 workspace
  • 如何动态更改字体名称?

    我正在使用 Jasper jar 生成有关我的 J2EE 项目的报告 我能够成功生成 PDF 没有任何问题 但是 我希望根据我们在一处配置的设置动态更改所有 PDF 的字体名称 我开始了解条件样式 这对于完成此任务很有用 然而 我确实有数百
  • AFNetworking 的 setImageWithURLRequest 在滚动后在错误的单元格中设置图像(iOS、Swift)

    我使用表dequeueReusableCellWithIdentifier and afnetworking uiimageview 我的一些细胞有图像 有些则没有 如果我在加载图像之前滚动表格 成功块会将图像放入重复使用的错误单元格中 例
  • 输入字段内的占位符自动换行

    我需要放一个很长的placeholder输入字段内的文本 但是 那placeholder由于文字较长 将被剪掉
  • 随机无效视图状态错误

    我知道关于这个主题有很多问题 我已经阅读了所有这些问题 我正在使用 IIS8 Net 4 5 用户随机收到无效视图状态错误 我无法弄清楚 一旦发生这种情况 他们返回网站的唯一方法就是清除浏览器缓存 在我的 web config 中我有
  • 如何在 [Authorize(Roles="")] 中使用变量

    我有一个 MVC 5 C Intranet Web 应用程序 其中使用了 30 多个 Active Directory 角色 并且由于业务文化的原因 权限经常发生变化 为了让事情变得简单 我想我应该尝试这样的事情来确定谁可以访问控制器操作或
  • 如何使 XML 文件始终在文本编辑器而不是 XML 编辑器中打开?

    我去档案协会那里没有 xml格式 当我添加它时 所有编辑器都会自动添加 并且它们是静态的 如下所示 locked by XML content type 无法删除关联 我希望每当我创建 XML 文件时 它都会用文本编辑器自动打开 请帮忙 单
  • 如何在Android首选项中正确接收和存储本地目录/路径?

    我想存储一个本地路径 内部或外部存储 用户可以在其中存储一些数据作为 Android 应用程序中的首选项 我希望用户在首选项中选择一个首选文件夹 默认文件夹是context externalMediaDirs它返回一个File我将其绝对路径
  • 具有类类型的 Java 反射 getDeclaredMethod()

    我试图理解 Java 反射 但在使用非整数 setter 方法时遇到困难 例如 如何解析下面的 getDeclaredMethod 调用 import java lang reflect class Target String value
  • Keras LSTM 密集层多维输入

    我正在尝试创建一个 keras LSTM 来预测时间序列 我的 x train 形状像 3000 15 10 示例 时间步长 特征 y train 形状像 3000 15 1 我正在尝试构建一个多对多模型 每个序列 10 个输入特征产生 1
  • 使用位移可视化 NER 训练数据和实体

    我创建了一个用于训练 NER 数据的数据集 创建后 我想在应用于训练管道之前测试实体和数据是否匹配 使用置换 我们可以以更好的方式进行可视化 但在 spacy 3 中如何做到这一点呢 上述问题的代码如下 import spacy from
  • 将阿拉伯文本分配给 R 变量

    R 无法正确显示阿拉伯文本 当我使用阿拉伯语时 我得到了非常奇怪的东西 这是一个屏幕截图 问题是我想创建一个带有阿拉伯文本的词云 我需要首先解决这个问题 R 版本 R 2 15 2 GUI 1 53 Leopard 版本 64 位 6335
  • RadGridView检测CellClick事件按钮

    如何检测在事件 CellClick 中按下了哪个鼠标按钮 或者如何检测在事件 MouseClick 中按下了哪个单元格 您可以使用鼠标单击事件检测单击了哪个单元格 然后你必须将 sender 转换为 RadGridView 然后使用 Cur
  • Room 分页无法正确地将 Flow> 与其他流合并

    我正在尝试使用Paging 3库来获取Flow