1、准备工作
接下来,您将学习如何在Android应用中使用LiveData 构建器
组合Kotlin 协程
和LivaData。我们还将使用协程异步flow,协程库中的该flow类型用于表示值的异步序列(或数据流),以实现相同的功能。
您将从一款使用Android架构组件
构建的现有应用入手,该应用使用LiveData
从Roow
数据库获取对象列表,然后在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、前提条件
- 具有使用
ViewModel
、LiveData
、Repository
和Room
架构组件的经验。 - 具有使用Kotlin语法(包括扩展函数和lambda)的经验
- 具有使用Kotlin协程的经验
- 对于在Android上使用线程(包括主线程、后台线程和回调)有基本的了解
1.2、应执行的操作
- 转换现有的
LiveData
,从而使用支持Kotlin协程的LiveData
构建器。 - 在
LiveData
构建器中添加逻辑。 - 使用
Flow
执行异步操作。 - 合并
Flows
并转换多个异步源。 - 使用
Flows
控制并发。 - 了解如何在
LiveData
和Floww
之间做选择。
2、准备设置
从命令行使用下列命令克隆 GitHub 代码库:
$ git clone https://github.com/googlecodelabs/kotlin-coroutines.git
此 Codelab 的代码位于 advanced-coroutines-codelab
目录中。
3、运行初始示例应用
首先,我们来看看起始示例应用的外观。按照下列说明在Android Studio中打开示例应用。
- 如果已下载
kotlin-coroutines
zip文件,请将其解压缩。 - 在Android Studio中打开
advanced-coroutines-codelab
目录。 - 确保在配置下拉菜单中选择了
start
。 - 点击Run
按钮,然后选择模拟设备或连接您的Android设备。该设备必须能够运行Android Lolipop(支持的最低SDK版本为21)。
应用首次运行时,系统会显示一个卡片列表,每张卡片上显示特定植物的名称和图片:
每个Plant
都有一个growZoneNumber
,该属性表示植物最可能生长的区域。用户可以点按过滤器图标,在显示全部植物以及显示某个特定生长区域(硬编码为区域9)的植物之间进行切换。多次按下过滤器按钮可以实际查看该过程。
3.1、架构概览
此应用使用架构组件将MainActivity
和PlantListFragment
中的界面代码与PlantListViewModel
的应用逻辑分隔开。PlantRepository
在ViewModel
与PlantDao
之间架起了一座桥梁,它可访问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
是一个内嵌类,仅包含表示其区域的Int
。NoGrowZone
表示某个区域不存在,仅用于过滤。
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)
虽然大多数代码修改在PlantListViewModel
和PlantRepository
中进行,但建议您花一点时间了解项目结构,重点关注朱武数据如何经过不同层从数据库流到Fragment
。