При разбивке на страницы с комнатой не удается правильно объединить поток <PagingData <Model>> с другими потоками
Я пытаюсь использовать библиотеку, чтобы получить от
Room
, затем проверьте, был ли выбран элемент в recyclerview, поэтому я сопоставляю этот класс с другим классом с именем. Для достижения этого сопоставления всякий раз, когда пользователь отмечал элемент как выбранный, я обновлялся внутри
MutableStateFlow<Map<Int, State>>
. Здесь смотрит вверх
Index(Int)
получить, это просто
enum
класс для представления государства
UNINITIALISED
,
USELECTED
а также
SELECTED
.
Я устанавливаю для карты значение. Проблема в том, что я пытаюсь объединить
Flow<PagingData<Scan>>
с, чтобы также передать как параметр в
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>>
Обновленная функция в 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
)
Мой источник подкачки внутри Дао
@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)
}
Инициализация карты для идентификаторов, присутствующих в комнате
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)
}
}
}
это
StateFlow<PagingData<ScanMapper>?>
.
Вот как я обновляю
Map
когда элемент выбирается пользователем в recyclerview.
fun markSelected(scanId: Int) {
val map = _myMap.value.toMutableMap()
map[scanId] = State.SELECTED
_myMap.value = map
}
Тогда я собираю это
myFlow
в моем
fragment
как это:
lifecycleScope.launchWhenStarted {
mainViewModel.getScansSyncFlow(requireContext())
mainViewModel.myFlow.collect { data ->
data?.let {
adapter.submitData(it)
}
}
}
1 ответ
Непосредственная проблема, которую я вижу, заключается в том, что вы используете collect вместо collectLatest. Поскольку submitData не возвращается, вы никогда не будете получать обновления из вашего Flow.
mainViewModel.myFlow.collectLatest {
adapter.submitData(it)
}