Android结合kotlin使用coroutine的方法实例
最近入了Android坑,目前还处于疯狂学习的状态,所以很久都没有写博客了。今天记录一个小代码片段,在Android上使用coroutine的小例子。
由于我自己是做一个记账软件来学习的,我用了gRPC,最开始我是使用线程来做网络请求的:
thread{ //网络请求代码 runOnUiThread{ //更新UI的代码 } }
今天把这一套全部重写成用coroutine。
首先coroutine得有个调度器,英文叫做“Dispatchers”,有这么几个:
- Dispatchers.Main这里面的coroutine跑在主线程上,在Android里也就是UI线程,所以如果在这里面的coroutine也执行大量耗时代码的话,也是会卡UI的
- Dispatchers.IO用来跑大IO的
- Dispatchers.Default用来跑高CPU消耗的
- Dispatchers.Unconfined不绑定在任何特定执行线程上
然后,为了多个coroutine之间可以分组啊,就像进程里可以放很多线程那样,又搞了一个概念,叫做scope,默认有一个全局scope,叫做GlobalScope,全局的,就和全局变量一样,在Android上,这个里面跑的coroutine,生命周期和app一样久,不推荐在这里起coroutine。
推荐的方式是每个Activity里起一个scope,然后再launch。
所以我就这样写基类:
abstractclassBaseActivity:AppCompatActivity(),CoroutineScope{ /* 默认的coroutinescope是Main,也就是UI线程(主线程)。如果要做IO,比如网络请求,记得 包裹在launch(Dispatchers.IO){}里,如果要大量计算,包裹在launch(Dispatcher.Default){}里 或者直接写launch。UI操作则用withContext(Dispatchers.Main){}切回来 */ privatevaljob=SupervisorJob() overridevalcoroutineContext:CoroutineContext get()=Dispatchers.Main+job overridefunonDestroy(){ super.onDestroy() coroutineContext.cancelChildren() }
这样子之后,就可以直接launch,起coroutine了:
launch{ valreq=CreateFeedbackReq.newBuilder().build() valrespAny=callRPC{ api.createFeedback(req) } respAny?:return@launch valresp=respAnyasCreateFeedbackResp if(handleRespAction(resp.action)){ withContext(Dispatchers.Main){ showSnackBar(R.string.thank_you_for_feedback) delay(1000) finish() } } }
如上,默认情况下,rootcoroutine就是当前所在activity,而他们默认会在Dispatchers.Main上执行,如果想要coroutine在别的dispatcher上执行,就用withContext,然后里面如果又想更新UI的话,就用withContext(Dispatchers.Main)。
那为啥launch不传参数的话,就是直接用的Dispatchers.Main呢?因为其实CoroutineScope是一个接口,而coroutineContext是里面的一个变量:
publicinterfaceCoroutineScope{ /** *Thecontextofthisscope. *Contextisencapsulatedbythescopeandusedforimplementationofcoroutinebuildersthatareextensionsonthescope. *Accessingthispropertyingeneralcodeisnotrecommendedforanypurposesexceptaccessingthe[Job]instanceforadvancedusages. * *Byconvention,shouldcontainaninstanceofa[job][Job]toenforcestructuredconcurrency. */ publicvalcoroutineContext:CoroutineContext }
我们再来看看launch的实现:
publicfunCoroutineScope.launch( context:CoroutineContext=EmptyCoroutineContext, start:CoroutineStart=CoroutineStart.DEFAULT, block:suspendCoroutineScope.()->Unit ):Job{ valnewContext=newCoroutineContext(context) valcoroutine=if(start.isLazy) LazyStandaloneCoroutine(newContext,block)else StandaloneCoroutine(newContext,active=true) coroutine.start(start,coroutine,block) returncoroutine } @ExperimentalCoroutinesApi publicactualfunCoroutineScope.newCoroutineContext(context:CoroutineContext):CoroutineContext{ valcombined=coroutineContext+context valdebug=if(DEBUG)combined+CoroutineId(COROUTINE_ID.incrementAndGet())elsecombined returnif(combined!==Dispatchers.Default&&combined[ContinuationInterceptor]==null) debug+Dispatchers.Defaultelsedebug }
可以看到,默认情况下,会把当前的coroutineContext放在前面。
Kotlin的coroutine很好用,不过我感觉还是有点复杂,我也还在学习。
ref:
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html
到此这篇关于Android结合kotlin使用coroutine的文章就介绍到这了,更多相关Android结合kotlin使用coroutine内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!