Coroutines在Android中的实践

前面两篇文章讲了协程的基础知识和协程的通信.
见:

这篇我们就从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.

coroutineScopesupervisorScope可以用来在suspend方法中启动协程. Structured concurrency保证: 当一个suspend函数返回时, 它的所有工作都执行完毕.

它们两者的区别是: 当子协程发生错误的时候, coroutineScope会取消scope中的所有的子协程, 而supervisorScope不会取消没有发生错误的其他子协程.

Activity/Fragment & Coroutines

在Android中, 可以把一个屏幕(Activity/Fragment)和一个