问题描述
我正在尝试使用 Paging 3
库从 Flow<PagingData<Scan>>
获取 Room
,然后检查是否在 recyclerview 中选择了项目,因此我将此类映射到另一个类称为 ScanMapper
。为了实现这种映射,每当用户将一个项目标记为选中时,我都会在 Map
中更新 MutableStateFlow<Map<Int,State>>
。这里 Map
查找 Index(Int)
以获得 State
,State
只是一个 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
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>
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)
}