Kotlin Flow和LiveData的高级协程(第一趴)

1,135 阅读4分钟

1、准备工作

接下来,您将学习如何在Android应用中使用LiveData 构建器组合Kotlin 协程和LivaData。我们还将使用协程异步flow,协程库中的该flow类型用于表示值的异步序列(或数据流),以实现相同的功能。

您将从一款使用Android架构组件构建的现有应用入手,该应用使用LiveDataRoow数据库获取对象列表,然后在RecyclerView网格布局中显示这些对象。

下面给出了一些代码段,从中您可以大致了解将要进行的操作。下面是用于查询Room数据库的线程代码:

val plants: LiveData<List<Plant>> = plantDao.getPlants()

系统将结合使用LiveData构建器和具有其他排序逻辑的协程更新LiveData

val plants: LiveData<List<Plant>> = liveData<List<Plant>> {
    val plantsLiveData = plantDao.getPlants()
    val customSortOrder = plantsListSortOrderCache.getOrAwait()
    emitSource(plantsLiveData.map { plantList -> plantList.applySort(customSortOrder) }
}

您还可以使用Flow实现相同的逻辑:

private val customSortFlow = plantsListSortOrderCache::getOrAwait.asFlow()

val plantsFlow: Flow<List<Plant>>
    get() = plantDao.getPlantsFlow()
        .combine(customSortFlow) { plants, sortOrder ->
            plants.applySort(sortOrder)
        }
        .flowOn(defaultDispatcher)
        .conflate()

1.1、前提条件

  • 具有使用ViewModelLiveDataRepositoryRoom架构组件的经验。
  • 具有使用Kotlin语法(包括扩展函数和lambda)的经验
  • 具有使用Kotlin协程的经验
  • 对于在Android上使用线程(包括主线程、后台线程和回调)有基本的了解

1.2、应执行的操作

  • 转换现有的LiveData,从而使用支持Kotlin协程的LiveData构建器。
  • LiveData构建器中添加逻辑。
  • 使用Flow执行异步操作。
  • 合并Flows并转换多个异步源。
  • 使用Flows控制并发。
  • 了解如何在LiveDataFloww之间做选择。

2、准备设置

从命令行使用下列命令克隆 GitHub 代码库:

$ git clone https://github.com/googlecodelabs/kotlin-coroutines.git

此 Codelab 的代码位于 advanced-coroutines-codelab 目录中。

3、运行初始示例应用

首先,我们来看看起始示例应用的外观。按照下列说明在Android Studio中打开示例应用。

  1. 如果已下载kotlin-coroutineszip文件,请将其解压缩。
  2. 在Android Studio中打开advanced-coroutines-codelab目录。
  3. 确保在配置下拉菜单中选择了start
  4. 点击Runexecute.png 按钮,然后选择模拟设备或连接您的Android设备。该设备必须能够运行Android Lolipop(支持的最低SDK版本为21)。

应用首次运行时,系统会显示一个卡片列表,每张卡片上显示特定植物的名称和图片:

image.png

每个Plant都有一个growZoneNumber,该属性表示植物最可能生长的区域。用户可以点按过滤器图标ee1895257963ae84.png,在显示全部植物以及显示某个特定生长区域(硬编码为区域9)的植物之间进行切换。多次按下过滤器按钮可以实际查看该过程。

image.png

3.1、架构概览

此应用使用架构组件将MainActivityPlantListFragment中的界面代码与PlantListViewModel的应用逻辑分隔开。PlantRepositoryViewModelPlantDao之间架起了一座桥梁,它可访问Room数据库并返回Plant对象列表。然后,界面会获取此植物列表,并在RecyclerView网格布局中显示这些植物。

代码库是ViewModel和数据之间的桥梁

代码库除了作为桥梁之外,还可以由任何希望使用其逻辑的ViewModel进行访问。它还可以合并来自多个数据源的逻辑,稍后我们将实现此操作。

在开始修改代码之前,让我们快速了解一下数据是如何从数据库流到界面的。下面介绍植物列表如何加载到ViewModel中:

PlantListViewModel.kt

val plants: LiveData<List<Plant>> = growZone.switchMap { growZone ->
    if (growZone == NoGrowZone) {
        plantRepository.plants
    } else {
        plantRepository.getPlantsWithGrowZone(growZone)
    }
}

GrowZone是一个内嵌类,仅包含表示其区域的IntNoGrowZone表示某个区域不存在,仅用于过滤。

Plant.kt

inline class GrowZone(val number: Int)
val NoGrowZone = GrowZone(-1)

点按过滤器按钮时,系统会对growZone进行切换。我们使用switchMap来确定要返回的植物列表。

switchMap对输入LiveData(本例中为growZone)应用给定的函数,并以LiveData形式返回转换后的结果。

用于从数据库中获取植物数据的代码库和数据方位对象(DAO)如下所示:

PlantDao.kt

@Query("SELECT * FROM plants ORDER BY name")
fun getPlants(): LiveData<List<Plant>>

@Query("SELECT * FROM plants WHERE growZoneNumber = :growZoneNumber ORDER BY name")
fun getPlantsWithGrowZoneNumber(growZoneNumber: Int): LiveData<List<Plant>>

PlantRepository.kt

val plants = plantDao.getPlants()

fun getPlantsWithGrowZone(growZone: GrowZone) = plantDao.getPlantsWithGrowZoneNumber(growZone.number)

虽然大多数代码修改在PlantListViewModelPlantRepository中进行,但建议您花一点时间了解项目结构,重点关注朱武数据如何经过不同层从数据库流到Fragment