什么是Kotlin协程
协程通过将复杂性放入库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。该库可以将用户代码的相关部分包装为回调、订阅相关事件、在不同线程(甚至不同机器)上调度执行,而代码则保持如同顺序执行一样简单。
协程就像非常轻量级的线程。线程是由系统调度的,线程切换或线程阻塞的开销都比较大。而协程依赖于线程,但是协程挂起时不需要阻塞线程,几乎是无代价的,协程是由开发者控制的。所以协程也像用户态的线程,非常轻量级,一个线程中可以创建任意个协程。
引用库
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
开启协程
- runBlocking
fun runBlocking() = runBlocking {
repeat(5) {
Log.i("minfo", "协程执行$it,当前线程id:${Thread.currentThread().id}")
delay(1000)
}
}

runBlocking启动的协程任务会阻断当前线程,直到该协程执行结束。
2.launch
fun launch() {
var job: Job = GlobalScope.launch {
repeat(5) {
Log.i("minfo", "协程执行$it,当前线程id:${Thread.currentThread().id}")
delay(1000)
}
}
}

launch启动的协程不会阻断当前线程。
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
launch() 是CoroutineScope的一个扩展函数,CoroutineScope简单来说就是协程的作用范围。CoroutineScope.launch返回类型为Job类型。
取消协程
GlobalScope.launch返回对象job可直接调用cancel取消协程。
job.cancel()
协程下上文
上下文有一个重要的作用就是线程切换,Kotlin协程使用调度器来确定哪些线程用于协程执行,Kotlin提供了调度器给我们使用:
Dispatchers.Main:在主线程中运行协程
Dispatchers.IO:在线程池中执行协程
Dispatchers.Default:在线程池中执行协程
Dispatchers.Unconfined:在当前调用的线程中执行
协程体
协程体是一个用suspend关键字修饰的一个无参,无返回值的函数类型。被suspend修饰的函数称为挂起函数,与之对应的是关键字resume。
那我们写一个模拟切到子线程进行耗时操作:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//开启一个协程,切换到主线程
GlobalScope.launch(Dispatchers.Main) {
tvContent.text = loadData()
}
}
/**
* 模拟访问接口获取接口数据
*/
suspend fun loadData(): String {
var response = ""
withContext(Dispatchers.IO) {
//子线程中模拟耗时操作
for (i in 0..10000000) {
}
response = "response"
}
return response
}
}
loadData方法将协程挂起,协程中其后面的代码永远不会执行,只有等到loadData挂起结束恢复后才会执行。
Retrofit结合协程使用:
Retrofit从2.6.0开始已经支持协程了,如果在网络请求框架中,引入Rxjava仅仅用来与Retrofit结合使用,那就太没有必要了。我们可以用协程来代替Rxjava这部分的功能。
在ApiService类中声明一个请求函数 ,声明为挂起函数,类型不需要添加Call。
interface ApiService {
@GET("v7/index/tab/discovery")
suspend fun getFindData(): BaseResponse
}
返回数据实体类:
open class BaseResponse : Serializable {
var count: Int = 0
var total: Int = 0
var nextPageUrl: String? = null
var adExist: Boolean? = false
}
协程结合retrofit使用
fun retrofitUse() {
var retrofit = Retrofit.Builder()
.baseUrl("http://baobab.kaiyanapp.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
GlobalScope.launch(Dispatchers.Main) {
try { //try catch同于onFailure的回调
tvContent.text = apiService.getFindData().toString()
} catch (e: Exception) {
tvContent.text = e.toString()
}
}
}
网友评论