個人博客
Kotlin的協程
前言
本文是Kotlin協程的一個簡單筆記,由於剛接觸Kotlin語言,如有理解錯誤,為避免誤導別人,可留言評論,以便本人及時修改,感謝各位大佬!關於協程的進階文章,可參考其它相關資料!
協程是什么
協程是一種
並發設計
模式,在Android
平台上使用它來簡化異步執行
的代碼。
以上是官方文檔對協程的簡單定義。
下面通過代碼來展示協程的具體使用。
假設有以下的需求:有一個耗時的任務要執行,在執行完成后,需要在主線程刷新UI。
不使用協程
在Activity的onCreate中分別調用以下方法
io()
ui()
private fun io() {
thread {
Log.d(TAG, "io method,thread:${Thread.currentThread().name}")
delay(1000)
}
}
private fun ui() {
Log.d(TAG, "ui method,thread:${Thread.currentThread().name}")
}
輸出日志:
2020-09-25 23:10:25.854 5208-5208/com.wangyz.coroutines D/Coroutine: ui method,thread:main
2020-09-25 23:10:25.855 5208-5267/com.wangyz.coroutines D/Coroutine: io method,thread:Thread-2
分別調用io()和ui()方法,兩個方法分別運行在子線程和主線程中,但是由於子線程的耗時操作,主線程方法先執行了,這樣就沒有達到我們想要的順序執行的效果。
修改代碼:
io2()
private fun io2() {
thread {
Log.d(TAG, "io method,thread:${Thread.currentThread().name}")
delay(1000)
runOnUiThread {
ui2()
}
}
}
private fun ui2() {
Log.d(TAG, "ui method,thread:${Thread.currentThread().name}")
}
在子線程中通過runOnUiThread將線程切換到主線程中來,輸出結果:
2020-09-25 23:16:44.753 5597-5641/com.wangyz.coroutines D/Coroutine: io method,thread:Thread-2
2020-09-25 23:16:45.756 5597-5597/com.wangyz.coroutines D/Coroutine: ui method,thread:main
再來看下協程的實現方式
使用協程
依賴項信息
如需在Android項目中使用協程,需要將以下依賴項添加到應用的 build.gradle 文件中:
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}
協程的使用
GlobalScope.launch(Dispatchers.Main) {
io3()
ui3()
}
private suspend fun io3(){
withContext(Dispatchers.IO){
Log.d(TAG, "io method,thread:${Thread.currentThread().name}")
delay(1000)
}
}
private fun ui3() {
Log.d(TAG, "ui method,thread:${Thread.currentThread().name}")
}
通過launch方法開啟一個協程,通過設置Dispatchers.Main運行在Main線程中,在io3中,通過withContext開啟一個線程,並通過設置Dispatchers.IO運行在IO線程。suspend是一個標記,表示這個方法內部會有掛起的操作,它並不會導致線程切換,真正切換線程是通過withContext來切換的。
輸出結果:
2020-09-25 23:28:19.965 6017-6062/com.wangyz.coroutines D/Coroutine: io method,thread:DefaultDispatcher-worker-1
2020-09-25 23:28:20.969 6017-6017/com.wangyz.coroutines D/Coroutine: ui method,thread:main
假設我們需要同時請求多個接口,並在這些接口全部返回數據后再統一更新界面,下面用協程來模擬實現這個需求。
請求多個異步接口
GlobalScope.launch(Dispatchers.Main) {
val res1 = async { io4() }
val res2 = async { io5() }
val data = res1.await() + res2.await()
ui4(data)
}
private suspend fun io4() = withContext(
Dispatchers.IO
) {
delay(2000)
Log.d(TAG, "io method,thread:${Thread.currentThread().name}")
1
}
private suspend fun io5() = withContext(
Dispatchers.IO
) {
delay(3000)
Log.d(TAG, "io method,thread:${Thread.currentThread().name}")
2
}
private fun ui4(value: Int) {
Log.d(TAG, "ui method,thread:${Thread.currentThread().name},result:${value}")
}
輸出結果:
2020-09-25 23:51:28.161 6495-6536/com.wangyz.coroutines D/Coroutine: io method,thread:DefaultDispatcher-worker-1
2020-09-25 23:51:29.389 6495-6537/com.wangyz.coroutines D/Coroutine: io method,thread:DefaultDispatcher-worker-2
2020-09-25 23:51:29.390 6495-6495/com.wangyz.coroutines D/Coroutine: ui method,thread:main,result:3
方法io4執行2秒,方法io5執行3秒,在io5執行完成后,將他們的結果相加再通過ui4更新到UI上。