Kotlin Coroutine 协程使用 &原理

1,560 阅读2分钟

1)Coroutine 是啥?

 Kotlin的一个特性::协程,可以理解为线程池的上层封装,一个线程上面可以跑多个协程;
 个人认为协程最主要有特性:
 1)流式代码,简洁,用近乎同步的代码写出异步操作。
 2)和viewmodel搭配使用,管理了协程生命,有效防止内存泄露。

有啥特性?

 个人认为比较好用的特性
 1)取代RxJava,优美的流式代码。
 2)便捷的线程切换,用线程池实现线程切换,比如从Main线程切换到IO线程。
 3)轻松实现异步(yield & resume),比如从网络请求数据,协程yield出去,等网络返回数据之后,协程resume获取执行。
 4)suspend 挂起关键字,很好的规范了代码,降低主线程被阻塞的概率。

2)Coroutine怎么用?

 GlobalScope.launch(Dispatchers.Main){
 //do something
 }
 
 GlobalScope.async(Dispatchers.IO){
 //do something
 }.await()

3)原理

1)协程挂起的原理?

 挂起实际上就是切线程,挂起协程,需要满足以下两个条件
 1)fun 用suspend 挂起关键字修饰
 2)挂起函数(withContext()/delay()/async{}.await())
 
 下面以为例,
 CoroutineScope(Dispatchers.Main).launch {
     getAllInfo()
}
 
 suspend fun getAllInfo(): LiveData<List<T>> {
    return viewModelScope.async(Dispatchers.IO) {
        return@async repository.getAllInfo()
    }.await()
}

 
kotlin 编译器会把上面协程编译成一个继承BaseContinuationImpl的实现,invokeSuspend 就是协程的block 方法了。

SuspendLambda 继承自BaseContinuationImpl
  
final class VideoListView$subscribeUi$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
Object L$0;
Object L$1;
int label;
private CoroutineScope p$;
final /* synthetic */ VideoListView this$0;

public final Object invokeSuspend(Object $result) {
    Object obj;
    Fragment it;
    Object coroutine_suspended = IntrinsicsKt.getCOROUTINE_SUSPENDED();
    int i = this.label;
    if (i == 0) {
        ResultKt.throwOnFailure($result);
        CoroutineScope $this$launch = this.p$;
        StringBuilder sb = new StringBuilder();
        sb.append("launch-currentThread:");
        sb.append(Thread.currentThread());
        LoggerUtil.i("GlobalScope", sb.toString());
        Fragment it2 = this.this$0.getFragment();
        if (it2 != null) {
            MediaInfoViewModel access$getMediaInfoViewModel$p = this.this$0.getMediaInfoViewModel();
            this.L$0 = $this$launch;
            this.L$1 = it2;
            this.label = 1;
            obj = access$getMediaInfoViewModel$p.getAllInfo(this);
            if (obj == coroutine_suspended) {
                return coroutine_suspended;//(1) async(Dispatchers.IO){}.await()挂起了协程
            }
            it = it2;
        }
        return Unit.INSTANCE; 
    } else if (i == 1) {
        it = (Fragment) this.L$1;
        CoroutineScope $this$launch2 = (CoroutineScope) this.L$0;
        ResultKt.throwOnFailure($result);
        obj = $result;
    } else {
        throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
    }
    ((LiveData) obj).observe(it, new VideoListView$subscribeUi$1$invokeSuspend?inlined$let$lambda$1(this));
    return Unit.INSTANCE;
}


  总:
  1、利用 label的状态来做到协程的挂起,比如代码(1)通过async(Dispatchers.IO){}.await() 挂起,直接return了协程挂起。
  2、等IO线程执行完任务之后,又通知到协程 label =1 ,协程执行未完成的代码。

3)如何实现线程切换?

 在线程池调度,完成线程切换。