定義
Coroutine翻譯為協(xié)程煮嫌,Google翻譯為協(xié)同程序,一般也稱為輕量級(jí)線程抱虐,但需要注意的是線程是操作系統(tǒng)里的定義概念立膛,而協(xié)程是程序語言實(shí)現(xiàn)的一套異步處理的方法。
在Kotlin文檔中梯码,Coroutine定義為一個(gè)可被掛起的計(jì)算實(shí)例
配置
build.gradle中dependencies 添加下面2行宝泵,注意coroutine目前仍處于experiment階段,但Kotline官方保證向前兼容轩娶。
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.19.3"
}
實(shí)例
我們看一個(gè)簡(jiǎn)單Android示例:
activity_coroutine.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".coroutine.CoroutineActivity">
<TextView
android:id="@+id/tvHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.constraint.ConstraintLayout>
CoroutineActivity.kt
class CoroutineActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coroutine)
setup()
}
fun setup() {
launch(UI) { // launch coroutine in UI context
for (i in 10 downTo 1) { // countdown from 10 to 1
tvHello.text = "Countdown $i ..." // update text
delay(1000) // wait half a second
}
tvHello.text = "Done!"
}
}
}
運(yùn)行程序 tvHello從10倒計(jì)時(shí)顯示到1儿奶,最后顯示"Done!"
代碼分析:
我們重點(diǎn)分析setup()函數(shù)
launch(UI) {...} -----在UIcontext下啟動(dòng)coroutine
delay(1000) ----將當(dāng)前coroutine掛起1秒
看到這里你可能會(huì)疑惑,Android開發(fā)中不是禁止在主線程下做延遲或者阻塞操作嗎鳄抒?
我們回顧下Coroutine的定義:一個(gè)可被掛起的計(jì)算實(shí)例闯捎。
Coroutine不是線程,所以掛起Coroutine不會(huì)影響當(dāng)前線程的運(yùn)行许溅。
取消Coroutine運(yùn)行
我們修改下上面的代碼:
class CoroutineActivity : AppCompatActivity() {
lateinit var job:Job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coroutine)
setup()
}
fun setup() {
job = launch(CommonPool) { // launch coroutine in UI context
for (i in 10 downTo 1) { // countdown from 10 to 1
tvHello.text = "Countdown $i ..." // update text
delay(1000) // wait half a second
}
tvHello.text = "Done!"
}
}
override fun onPause() {
super.onPause()
job.cancel()
}
}
重點(diǎn)是 launch(UI)返回給一個(gè)job實(shí)例瓤鼻,通過job.cancel()取消coroutine。
Coroutine和thread關(guān)系
我們?cè)俜治鱿?/p>
launch(UI)
這行代碼是指將coroutine指派在UI線程上運(yùn)行
當(dāng)我們運(yùn)行一段cpu耗時(shí)操作時(shí)贤重,則需要將coroutine指定在非UI線程上茬祷。
我們寫成:
launch(){...}
這行代碼等價(jià)于:
launch(CommonPool){...}
我們分析下CommonPool的實(shí)現(xiàn),發(fā)現(xiàn)它會(huì)根據(jù)當(dāng)前cpu的核數(shù)創(chuàng)建一個(gè)線程池提供給Coroutine使用并蝗。
private fun createPlainPool(): ExecutorService {
val threadId = AtomicInteger()
return Executors.newFixedThreadPool(defaultParallelism()) {
Thread(it, "CommonPool-worker-${threadId.incrementAndGet()}").apply { isDaemon = true }
}
}
private fun defaultParallelism() = (Runtime.getRuntime().availableProcessors() - 1).coerceAtLeast(1)
總結(jié):
通過上面的分析祭犯,我們理解了Coroutine是一個(gè)運(yùn)行在線程上的可被掛起的計(jì)算單元實(shí)例秸妥,對(duì)Coroutine的delay,cancel操作不會(huì)影響線程的運(yùn)行,線程的狀態(tài)變化對(duì)我們是透明的沃粗,我們不需要關(guān)心粥惧。
所以使用Coroutine,可以使我們更加方便得處理異步操作最盅,比如網(wǎng)絡(luò)請(qǐng)求突雪,數(shù)據(jù)存儲(chǔ)等。