Kotlin Coroutines在Android中的实践
Coroutines在Android中的实践
前面两篇文章讲了协程的基础知识和协程的通信.
见:
- Kotlin Coroutines不复杂, 我来帮你理一理
- Kotlin协程通信机制: Channel
举的例子可能离实际的应用代码比较遥远.
这篇我们就从Android应用的角度, 看看实践中都有哪些地方可以用到协程.
Coroutines的用途
Coroutines在Android中可以帮我们做什么:
- 取代callbacks, 简化代码, 改善可读性.
- 保证Main safety.
- 结构化管理和取消任务, 避免泄漏.
这有一个例子:
suspend fun fetchDocs() { // Dispatchers.Main val result = get("developer.android.com") // Dispatchers.Main show(result) // Dispatchers.Main } suspend fun get(url: String) = // Dispatchers.Main withContext(Dispatchers.IO) { // Dispatchers.IO (main-safety block) /* perform network IO here */ // Dispatchers.IO (main-safety block) } // Dispatchers.Main }
这里get
是一个suspend
方法, 只能在另一个suspend
方法或者在一个协程中调用.
get
方法在主线程被调用, 它在开始请求之前suspend了协程, 当请求返回, 这个方法会resume协程, 回到主线程. 网络请求不会block主线程.
main-safety是如何保证的呢?
dispatcher决定了协程在什么线程上执行. 每个协程都有dispatcher. 协程suspend自己, dispatcher负责resume它们.
Dispatchers.Main
: 主线程: UI交互, 更新LiveData
, 调用suspend
方法等.Dispatchers.IO
: IO操作, 数据库操作, 读写文件, 网路请求.Dispatchers.Default
: 主线程之外的计算任务(CPU-intensive work), 排序, 解析JSON等.
一个好的实践是使用withContext()
来确保每个方法都是main-safe的, 调用者可以在主线程随意调用, 不用关心里面的代码到底是哪个线程的.
管理协程
之前讲Scope和Structured Concurrency的时候提过, scope最典型的应用就是按照对象的生命周期, 自动管理其中的协程, 及时取消, 避免泄漏和冗余操作.
在协程之中再启动新的协程, 父子协程是共享scope的, 也即scope会track其中所有的协程.
协程被取消会抛出CancellationException
.
coroutineScope
和supervisorScope
可以用来在suspend方法中启动协程. Structured concurrency保证: 当一个suspend函数返回时, 它的所有工作都执行完毕.
它们两者的区别是: 当子协程发生错误的时候, coroutineScope
会取消scope中的所有的子协程, 而supervisorScope
不会取消没有发生错误的其他子协程.
Activity/Fragment & Coroutines
在Android中, 可以把一个屏幕(Activity/Fragment)和一个