android - 为什么第二个代码可以安全地在 map 中进行网络调用,因为它已被缓存?

标签 android kotlin kotlin-coroutines android-livedata

我正在这样做codelab关于 Kotlin 协程。从第 6 步到第 7 步,我应该更新此方法:

fun getPlantsWithGrowZone(growZone: GrowZone) = liveData {
    val plantsGrowZoneLiveData = plantDao.getPlantsWithGrowZoneNumber(growZone.number) // db
    val customSortOrder = plantsListSortOrderCache.getOrAwait() // network
    emitSource(plantsGrowZoneLiveData.map { plantList ->
        plantList.applySort(customSortOrder)
    })
}

对于这个:

fun getPlantsWithGrowZone(growZone: GrowZone) =
    plantDao.getPlantsWithGrowZoneNumber(growZone.number) // db
        .switchMap { plantList ->
            liveData {
                val customSortOrder = plantsListSortOrderCache.getOrAwait() //network
                emit(plantList.applyMainSafeSort(customSortOrder))
            }
        }

Codelab 解释了第二个区别,即在 map 中进行网络调用是安全的,因为它已被缓存。但我不明白为什么?

最佳答案

对功能进行此更改似乎有两个目标,但第二个目标没有明确说明。

  1. 在与主线程不同的线程上进行排序,因此不会降低 UI 性能。
  2. 每次数据库更新植物列表时,都会从网络重新获取排序方法,以防排序方法发生更改。在前面的代码中,排序方法仅预先获取一次,然后在每次数据库中更新植物列表时重复使用,因此排序顺序可能会过时。

实现目标 1:

第 1 步是创建排序函数的一个版本,它是一个不在主线程上运行的挂起函数。 withContext 在挂起函数中使用,将排序移动到不同的线程(通过使用不同的调度程序指定)。

第2步是在映射数据时使用这个挂起函数。 liveData.map 函数的 lambda 无法调用挂起函数,因为它不是在协程中运行。它直接在主线程上运行。因此,我们必须改变绘制数据的方法。

使用 switchMap 包裹另一个 liveData { } 协程构建器 block 允许我们在调用挂起函数的同时映射数据。协程封装在使用协程构建器创建的新内部 LiveData 中。我相信当他们说“缓存”时,他们指的是这个内部 LiveData 对象,但术语有点模糊。


实现目标 2:

对于数据库植物列表的每次更改,我们已经改用 liveData { } 协程构建器,因此我们可以继续移动此 getOrAwait()暂停内部 LiveData 内部的函数调用,以便每次都会进行调用。


不过我们仍然遇到了一些问题。每当数据库列表发生变化时,我们都会得到最新的排序顺序,但如果数据库列表没有变化而排序顺序确实发生了变化,那么它就会过时。如果用 LiveData 来解决这个问题会非常复杂。但后来在 CodeLab 中,他们从 LiveData 切换到 Flow,并使用 Flow 的 combine 运算符解决了这个问题。

关于android - 为什么第二个代码可以安全地在 map 中进行网络调用,因为它已被缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76688785/

相关文章:

android - 混合应用程序中的下拉列表在某些 Android 设备上的灰色背景上有黑色文本

android - ConstraintLayout 内的 DrawerLayout

android - 在 JetPack Composable 中观察 LiveData

android - 如何更改 viewpager 中每个 fragment 的点指示器( Activity 和非 Activity )的颜色?

android - 在 ViewModel 中从 SqlDelight 收集流时出现 java.lang.IllegalStateException

android - 用作 LaunchedEffect 键时出现 NetworkOnMainThreadException

kotlin-coroutines - 如何从挂起方法调用 Observable 并等待结果

java - 如何在任何循环内使用 'wait' 命令?

android - 线图与 achartengine android

android - Jetpack 撰写 Material 设计 3 具有圆角边缘的卡片 View 未由图像或波纹动画填充