本文列举部分 Kotlin Github 项目中代码的实际使用等.
Kotlin-Coroutine-Use-Cases-on-Android
三方库
1 | apply plugin: 'kotlin-kapt' |
BaseViewModel 类
1 | open class BaseViewModel<T> : ViewModel() { |
- BaseViewModel 定义泛型,支持不同页面分别对应的不同的 UiState(定义见下面)
- 定义变量 uiState, 数据类型为 LiveData,且为 protected 修饰,即不可以在 Activity 中修改
- 定义函数 uiState(), 用来在 Activity 中观察
UiState 类
1 | sealed class UiState { |
- 定义当前页面对应的 UiState 类,同时再定义页面中需要的不用状态,这里分别是单例 Loading、成功的 Success、失败的 Error
PerformSingleNetworkRequestViewModel 类
1 | viewModelScope.launch { |
- viewModelScope.launch {} 创建协程作用域
- 网络请求获取的结果,创建 UiState.Success(recentAndroidVersions) 或者 UiState.Error(“Network Request failed!”), 并赋值给 uiState
PerformSingleNetworkRequestActivity 类
1 | private val viewModel: PerformSingleNetworkRequestViewModel by viewModels() |
- 通过 activity-ktx 库中的 viewModels() 代理懒加载 viewModel 对象
- 监听 BaseViewModel 中的 uiState(), 渲染 UI
Application 类
1 | override fun onCreate() { |
同时执行多个网络请求
1 | val oreoFeaturesDeferred = viewModelScope.async { mockApi.getAndroidVersionFeatures(27) } |
通过 awaitAll() 同时执行多个请求
给请求设置超时时间
1 | try { |
通过 withTimeout(timeout) 或者 withTimeoutOrNull(timeout), 设置超时时间
重试网络请求
1 | // retry with exponential backoff |
执行可变数量的网络请求
1 | val versionFeatures = recentVersions.map { androidVersion -> |
Room + 协程
Entity
1 |
|
Dao
1 |
|
Database (单例)
1 |
|
ViewModelFactory (想在 ViewModel 中传入 database)
1 | class ViewModelFactory(private val api: MockApi, private val database: AndroidVersionDao) : |
ViewModel
1 | class RoomAndCoroutinesViewModel( |
RoomAndCoroutinesActivity
1 | private val viewModel: RoomAndCoroutinesViewModel by viewModels { |
协程的调试
Application
1 | // Enable Debugging for Kotlin Coroutines in debug builds |
Extensions
1 | fun addCoroutineDebugInfo(message: String) = "[${Thread.currentThread().name}] $message" |
使计算协程代码可取消
如果协程正在执行计算任务,并且没有检查取消的话,那么它是不能被取消的。
但是有两种方法来使执行计算的代码可以被取消。第一种方法是定期调用挂起函数来检查取消, 对于这种目的 yield 是一个好的选择。 另一种方法是显式的检查取消状态。
1 | // factorial of n (n!) = 1 * 2 * 3 * 4 * ... * n |
异常处理
通过 try/catch 处理异常
1 | val exceptionHandler = CoroutineExceptionHandler { _, exception -> |
通过 CoroutineExceptionHandler 处理异常
1 | val exceptionHandler = CoroutineExceptionHandler { _, exception -> |
使用 supervisorScope, 在存在失败的协程的情况下不会取消其同级协程的情况
1 | viewModelScope.launch { |
使用 runCatching, 在存在失败的协程的情况下不会取消其同级协程的情况
1 | viewModelScope.launch { |