1. 定义
类似一种轻量级的线程。
线程是依靠操作系统的调度实现不同线程切换。协程仅在编程语言层面上实现不同协程之间切换。
协程实现利用依赖库:
dependencies {
...
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1" //andriod中用的
}
2. 作用域构建器
创建协程作用域:
- 使用GlobalScope.launch函数可以创建一个协程的作用域(顶层协程),这样传递给launch函数的代码块就是在协程
中运行的了。GlobalScrope.launch函数创建的永远是顶层协程。
- runBlocking函数也会创建一个协程的作用域,但它可以保证在协程作用域内的所有代码和子协程没有全部执行完之
一直阻塞当前线程。通常只应在测试环境下使用,正式环境中使用会产生性能上问题。
创建一个协程并获取它的执行结果:
利用async函数,该函数必须在协程作用域当中才能调用。
获取async函数代码块的执行结果,只需要调用Deferred对象的await()方法。
fun main() {
runBlocking {
val result = async {
5 + 5
}.await()
println(result)
//当调用await()方法时,如果代码块中的代码还没执行完,那么await()方法会将当前协程阻塞住,直到可以获
//得async函数的执行结果
}
}
创建多个协程:
使用launch函数。该函数必须在协程的作用域中才能调用,其次会在当前线程的作用域下创建子协程。
子协程的特点是如果外层作用域的协程结束,该作用域下的所有子协程也会一同结束。
挂起函数:
suspend关键字可以将任意函数声明成挂起函数,而挂起函数之间都是可以互相调用的。
suspend无法给函数提供协程作用域。
suspend fun printDot() {
println(".")
delay(1000)
}
coroutineScope函数是一个挂起函数,特点是会继承外部的协程的作用域并创建一个子协程。
这样就可以给任意挂起函数提供协程作用域了。
suspend fun printDot() = coroutineScope {
launch {
println(".")
delay(1000)
}
}
withContext()函数也是挂起函数,是async函数的一种简化版写法。
该函数强制要求指定一个线程参数:
Dispatchers.Default:默认低并发的线程策略
Dispatchers.IO:较高并发的线程策略;
Dispatchers.Main:不会开启子线程,而是在Android主线程中执行代码;
fun main() {
runBlocking {
val result = withContext(Dispatchers.Default) {
5 + 5
}
println(result)
}
}
3. 实际项目常用写法
val job = Job()
val scope = CoroutineScope(job)
scope.launch{
//处理具体逻辑。但是返回值是个job对象,不能获取执行的结果
}
job.cancel() //取消协程
//这样所有调用CoroutineScope的launch函数多创建的协程,都会被关联在Job对象的作用域下面
4. 利用协程简化回调:
借助suspendCoroutine函数能够将传统回调机制的写法大幅简化。
该函数必须在协程作用域或挂起函数中才能调用。接收一个Lambda表达式参数,主要作用是将当前协程挂起,然后在一个普通的
线程中执行Lambda表达式的代码。Lambda表达式的参数列表上会传入一个Continuation参数。调用它的resume()方法或
rusumeWithException()可以让协程恢复执行。
suspend fun request(address: String): String {
//在Lambda表达式中调用HttpUtil.sendHttpRequest()方法发起网络请求
return suspendCoroutine { continuation ->
HttpUtil.sendHttpRequest(address, object : HttpCallbackListener {
//请求成功,传入服务器响应的数据
override fun onFinish(response: String) {
continuation.resume(response)
}
//请求失败,传入具体异常原因
override fun onError(e: Exception) {
continuation.resumeWithException(e)
}
})
}
}
//调用:
suspend fun getBaiduResponse() {
try {
val response = request("https://www.baidu.com/") //当前协程立即挂起
// 协程恢复,对服务器响应的数据进行处理
} catch (e: Exception) {
// 对异常情况进行处理
}
}