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)如何实现线程切换?
在线程池调度,完成线程切换。