【问题标题】:How to filter LiveData List based on LiveData Map?如何根据 LiveData Map 过滤 LiveData List?
【发布时间】:2020-10-05 15:44:13
【问题描述】:

我要异步操作。在 viewmodel 中,两者需要一起为 UI 工作。如何根据 de LiveData 地图中的键过滤 LiveData 列表? (列表中的对象 id 对应于 Map 键)

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
private val _allJourneys = MutableLiveData<List<Journey>>()
val allJourneys: LiveData<List<Journey>> get() = _allJourneys

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
private val _enrolledMap = MutableLiveData<Map<String, String>>()
val enrolledMap: LiveData<Map<String, String>> get() = _enrolledMap

fun getEnrolled() {
    viewModelScope.launch {
        progressRepository.getEnrolledJourneysMapOfUser().observeForever {
            Timber.d("Map values: $it")
            _enrolledMap.value = it
        }
    }

}

fun getJourneys() {
    viewModelScope.launch {
        journeysRepository.getAll().observeForever { it ->
            _allJourneys.value = it.filter {
               // enrolledMap.containsKey(it.id) ??? Nullpointer
            }
        }
    }
}

【问题讨论】:

  • 您想根据注册地图键过滤旅程,对吗?使用transformations 怎么样?通过这种方式,您可以将观察者移动到 UI 并传递 LiveData 引用。 MediatorLiveData 也很有用
  • @Stachu 感谢您的评论。在架构中的什么时候,我会根据地图过滤旅程?我正在使用 MVVM 和 Cloud Firestore。
  • journeysRepository.getAll()progressRepository.getEnrolledJourneysMapOfUser() 返回LiveData?
  • @Stachu LiveData>,确实如此。

标签: kotlin android-livedata mutablelivedata


【解决方案1】:

这样的事情怎么样(基于来自here 的 MediatorLiveData 示例)

    val allJourneys: LiveData<List<Journey>> = journeysRepository.getAll()
    val enrolledMap: LiveData<Map<String, String>> = progressRepository.getEnrolledJourneysMapOfUser()

    private val _filteredJourneys = MediatorLiveData<List<Journey>>()
    private val filteredJourneys: LiveData<List<Journey>> = _filteredJourneys

    init {
        _filteredJourneys.addSource(allJourneys) {
            combineLatestData(allJourneys,enrolledMap)
        }
        _filteredJourneys.addSource(enrolledMap) {
            combineLatestData(allJourneys,enrolledMap)
        }
    }

    private fun combineLatestData(
        journeysLD: LiveData<List<Journey>>,
        enrolledLD: LiveData<Map<String, String>>
    ): List<Journey>? {
        val j = journeysLD.value
        val e = enrolledLD.value
        val result = listOf<Journey>()
        if (j == null || e == null) {
            return result // TODO filter j by e
        }
        return null
    }

allJourneyenrolledMap LiveData 中的更改应触发 combineLatestData

【讨论】:

  • 在顶部 val:挂起函数 'getAll' 只能从协程或其他挂起函数中调用
  • getAll 因 Cloud Firestore 而被暂停?对于 Room,我从不使用 LiveData 的挂起
  • 是的,取决于本地数据库是否为空,然后获取远程数据。
【解决方案2】:

observeForever 在 ViewModel 中是错误的方法。每次调用 get__ 时,都会创建一个新订阅,您将获得多个订阅,并且您的 ViewModel 中可能会出现内存泄漏,直到垃圾收集器清除卡住的订阅。

相反,当您使用 LiveData 时,您应该只使用返回值并将它们保留为字段。

val allJourneys: LiveData<List<Journey>> get() = journeysRepository.getAll()
    
val enrolledMap: LiveData<Map<String, String>> get() = progressRepository.getEnrolledJourneysMapOfUser()

//fun getEnrolled() {
//    viewModelScope.launch {
//        .observeForever {
//            Timber.d("Map values: $it")
//            _enrolledMap.value = it
//        }
//    }
//
//}

//fun getJourneys() {
//    viewModelScope.launch {
//        .observeForever { it ->
//            _allJourneys.value = it.filter {
//               // enrolledMap.containsKey(it.id) ??? Nullpointer
//            }
//        }
//    }
//}

因为来自 DAO 的存储库中的 LiveData 已经处理后台数据获取。

如果这是通过存储库中的挂起函数手动完成的,那么您可以使用 switchMap + liveData { emitSource - 但在这种情况下,似乎没有必要。

【讨论】:

  • 如果我将它们保留为字段,我会收到错误消息:“只能从协程或其他挂起函数调用挂起函数 'getAll'”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多