1.协程是什么?
kotlin中的协程是基于协程框架Coroutine实现的轻量级线程,提供一种简化处理异步任务的方式。
2.怎么使用协程?
使用协程框架中的launch方法包裹的代码块就是协程的内容,常规的代码如下:
val coroutineScope = CoroutineScope(context)
coroutineScope.launch {getImage(imageId)
}
在实际的项目中,我们通常使用ViewModel.viewModelScope来直接使用launch函数:
// 这里定义了一个高阶函数,便于其他调用的地方直接传入携程代码块
//viewModelScope.launch 函数用于创建并启动一个新的协程,以异步执行一段代码块,不会阻塞当前主线程
// viewModelScope是属于ViewModel的扩展属性,方便在ViewModel中使用协程,并且可以监测Activity或者Fragment的生命周期,然后自动取消,避免内存泄漏
private fun launch(block: suspend () -> Unit, error: suspend (Throwable) -> Unit) = viewModelScope.launch {try {block()} catch (e: Throwable) {error(e)}}
3.怎么理解挂起?
viewModelScope.launch {var heFengCity = repository.transPortAdCodeToLocationID(areaid)Toast.makeText(CoolWeatherApplication.context, heFengCity, Toast.LENGTH_SHORT)
}
......
suspend fun transPortAdCodeToLocationID(adcode: String) : HeFengCity = withContext(Dispatchers.IO) {var city = hefengNetWork.fetchFefengLocation(adcode)caCheCurrentName(city?.location?.get(0)?.name)city}
当执行到transPortAdCodeToLocationID函数的时候,launch中的协程代码就会被切换到另外的IO线程执行,相当于是在当前线程做了一个post的动作,并不会阻塞当前线程的继续执行。当协程代码中的transPortAdCodeToLocationID方法在IO线程执行完之后,会自动切换回之前的线程,并执行toast方法。这样在遇到suspend方法发生线程切换执行,在完成方法执行之后再切换回来原来线程的过程,就叫做挂起。
4.suspend关键字的作用
使用suspend关键字修饰的方法,表示这是一个挂起函数。但仅仅是有suspend,是不能实现挂起的动作的,挂起的动作是由协程内部框架帮我们实现的,即需要直接或者间接调用协程系统内部的suspend方法。比如这里的就调用了withContext方法,它就是协程框架提供的挂起函数。
同时,一个挂起函数,只能在协程代码块中被调用或者被另一个挂起函数调用,最终还是要在协程代码块中被调用,不然就会报错误:
fun getImage(imageId: Int) = withContext(Dispatchers.IO) {// IDE 报错 Suspend function'withContext' should be called only from a coroutine or another suspend funcion
}
5.什么是非阻塞式挂起
既然协程挂起可以实现切线程,那肯定就不会阻塞当前的线程了。至于为什么叫非阻塞式挂起,是因为在实现协程代码的时候,是使用了看似阻塞式的书写方式,但是又实现了非阻塞式的效果。如:
main {GlobalScope.launch(Dispatchers.Main) {val user = suspendingRequestUser() // 耗时操作updateView(user)}private suspend fun suspendingRequestUser() : User = withContext(Dispatchers.IO) {api.requestUser()}
}