关于Android-Kotlin协程,我们要牢记,它就是个线程框架,它的唯一作用是:
把异步代码用同步的方式来写!
用更容易理解的话来说,就是
由它来帮我们做切换线程的操作!
我尝试用伪代码的方式,把它描述清楚
以这样一段代码为例:
scope.launch(主线程) {
这里是一堆非suspend代码-01
withContext (IO线程) {
调用接口
}
这里是一堆非suspend代码-02
withContext (Work线程) {
数据排序
}
这里是一堆非suspend代码-03
}
对于线程来说,最重要的东西是Runnable,Android切换主线程,是Handler.post(Runnable),线程池执行任务,也是executor.execute(Runnable)。 既然协程的唯一作用就是帮我们切换线程,它必定逃不脱把代码转换为Runnable。
转换的第一步: 把scope内的代码直接变成Runnable
scope.launch(主线程) {
handler.post: new Runnable { 这里是一堆非suspend代码-01 }
IO线程池.execute: new Runnable { 调用接口 }
handler.post: new Runnable { 这里是一堆非suspend代码-02 }
Work线程池.execute: new Runnable { 数据排序 }
handler.post: new Runnable { 这里是一堆非suspend代码-03 }
}
这样,至少可以完成 切换线程 这一需求。只是现在它还不是串行的。
转换的第二步: 为了让它串行,需要先让它知道串行的顺序
想让它串行,就必须让原来的多个互不关联的Runnable之间产生关联,最简单的办法就是提供一个全局变量,由这个全局变量来记录当前执行到了哪一步。
每个Runnable执行完成后,就更新状态
scope.launch(主线程) {
int state = 0 // 我来记录当前执行到哪一步了
handler.post: new Runnable {
这里是一堆非suspend代码-01
state = 1
}
IO线程池.execute: new Runnable {
调用接口
state = 2
}
handler.post: new Runnable {
这里是一堆非suspend代码-02
state = 3
}
Work线程池.execute: new Runnable {
数据排序
state = 4
}
handler.post: new Runnable {
这里是一堆非suspend代码-03
state = 5
}
}
转换的第三步: 把它们串起来
顺序已经有了,把它们串行执行,就只需要一个中转处理
scope.launch(主线程) {
int state = 0 // 我来记录当前执行到哪一步了
Runnable1 = {
这里是一堆非suspend代码-01
state = 1
runnableDone()
}
Runnable2 = {
调用接口
state = 2
runnableDone()
}
Runnable3 = {
这里是一堆非suspend代码-02
state = 3
runnableDone()
}
Runnable4 = {
数据排序
state = 4
runnableDone()
}
Runnable5 = {
这里是一堆非suspend代码-03
state = 5
runnableDone()
}
void runnableDone() {
when (state):
0: handler.post Runnable1
1: IO线程池.execute Runnable2
2: handler.post Runnable3
3: Work线程池.execute Runnable4
4: handler.post Runnable5
5: 完成
}
}
start() -> ResumeWith(0) -> state=0 & runnableDone()
完成,原来的异步代码就变成了同步的形式。