Android入門教程 | Kotlin協程入門
Android官方推薦使用協程來處理非同步問題。
協程的特點:
- 輕量:單個執行緒上可執行多個協程。協程支援掛起,不會使正在執行協程的執行緒阻塞。掛起比阻塞節省記憶體,且支援多個並行操作。
- 記憶體洩漏更少:使用結構化併發機制在一個作用域內執行多項操作。
- 內建取消支援:取消操作會自動在執行中的整個協程層次結構內傳播。
- Jetpack整合:許多Jetpack庫都包含提供全面協程支援的擴充套件。某些庫還提供自己的協程作用域,可用於結構化併發。
示例
首先工程中需要引入 Kotlin 與協程。然後再使用協程發起網路請求。
引入: Android 工程中引入 Kotlin,參考 Android 專案使用 kotlin
有了Kt後,引入協程
1
2
3 |
dependencies {
implementation
"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
// 協程 } |
啟動協程
不同於 Kotlin 工程直接使用 GlobalScope,這個示例在
ViewModel中使用協程。需要使用
viewModelScope
。
下面的 CorVm1 繼承了 ViewModel。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
import
androidx.lifecycle.ViewModel import
androidx.lifecycle.viewModelScope
// 引入 import
kotlinx.coroutines.Dispatchers import
kotlinx.coroutines.launch class
CorVm1 : ViewModel() {
companion object {
const
val TAG =
"rfDevCorVm1"
}
fun cor1() {
viewModelScope.launch { Log.d(TAG,
"不指定dispatcher ${Thread.currentThread()}"
) }
} } |
在按鈕的點選監聽器中呼叫 cor1() 方法,可以看到協程是在主執行緒中的。
1 |
不指定dispatcher Thread[main,
5
,main] |
由於此協程透過
viewModelScope
啟動,因此在 ViewModel 的作用域內執行。如果 ViewModel 因使用者離開螢幕而被銷燬,則
viewModelScope
會自動取消,且所有執行的協程也會被取消。
launch()
方法可以指定執行的執行緒。可以傳入
Dispatchers
來指定執行的執行緒。
先簡單看一下
kotlinx.coroutines
包裡的 Dispatchers ,它有4個屬性:
-
Default
,預設 -
Main
,Android中指定的是主執行緒 -
Unconfined
,不指定執行緒 -
IO
,指定IO執行緒
都透過點選事件來啟動
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
// CorVm1.kt fun ioCor() {
viewModelScope.launch(Dispatchers.IO) {
Log.d(TAG,
"IO 協程 ${Thread.currentThread()}"
)
} } fun defaultCor() {
viewModelScope.launch(Dispatchers.Default) {
Log.d(TAG,
"Default 協程 ${Thread.currentThread()}"
)
} } fun mainCor() {
viewModelScope.launch(Dispatchers.Main) { Log.d(TAG,
"Main 協程 ${Thread.currentThread()}"
) } } fun unconfinedCor() {
viewModelScope.launch(Dispatchers.Unconfined) {
Log.d(TAG,
"Unconfined 協程 ${Thread.currentThread()}"
)
} } |
執行log
1
2
3
4 |
IO 協程 Thread[DefaultDispatcher-worker-
1
,
5
,main] Main 協程 Thread[main,
5
,main] Default 協程 Thread[DefaultDispatcher-worker-
1
,
5
,main] Unconfined 協程 Thread[main,
5
,main] |
從上面的比較可以看出,如果想利用後臺執行緒,可以考慮
Dispatchers.IO
。
Default
用的也是
DefaultDispatcher-worker-1
執行緒。
模擬網路請求
主執行緒中不能進行網路請求,我們把請求放到為IO操作預留的執行緒上執行。一些資訊用 MutableLiveData 發出去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 |
// CorVm1.kt val info1LiveData: MutableLiveData<String> = MutableLiveData() private
fun reqGet() {
info1LiveData.value =
"發起請求"
viewModelScope.launch(Dispatchers.IO) {
val url = URL(
"
"
)
try
{
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod =
"GET"
conn.connectTimeout =
10
*
1000
conn.setRequestProperty(
"Cache-Control"
,
"max-age=0"
)
conn.doOutput =
true
val code = conn.responseCode
if
(code ==
200
) {
val baos = ByteArrayOutputStream()
val inputStream: InputStream = conn.inputStream
val inputS = ByteArray(
1024
)
var len: Int
while
(inputStream.read(inputS).also { len = it } > -
1
) {
baos.write(inputS,
0
, len)
}
val content = String(baos.toByteArray())
baos.close()
inputStream.close()
conn.disconnect()
info1LiveData.postValue(content)
Log.d(TAG,
"net1: $content"
)
}
else
{
info1LiveData.postValue(
"網路請求出錯 $conn"
)
Log.e(TAG,
"net1: 網路請求出錯 $conn"
)
}
}
catch
(e: Exception) {
Log.e(TAG,
"reqGet: "
, e)
}
} } |
看一下這個網路請求的流程
- 從主執行緒呼叫
reqGet()
函式 -
viewModelScope.launch(Dispatchers.IO)
在協程上發出網路請求 - 在協程中進行網路操作。把結果傳送出去。
kotlin 協程相關知識點
1. 協程基礎
- 你的第一個協程程式
- 橋接阻塞與非阻塞的世界
- 等待一個任務
- 結構化的併發
- 作用域構建器
- 提取函式重構
- ......
2. 取消與超時
- 取消協程的執行
- 取消是協作的
- 使計算程式碼可取消
- 在 finally 中釋放資源
- 執行不能取消的程式碼塊
- 超時
3. 通道
- 通道基礎
- 關閉與迭代通道
- 構建通道生產者
- 管道
- 使用管道的素數
- 扇出
- 扇入
- 帶緩衝的通道
- 通道是公平的
- 計時器通道
4. 組合掛起函式
- 預設順序呼叫
- 使用 async 併發
- 惰性啟動的 async
- async 風格的函式
- 使用 async 的結構化併發
5. 協程上下文與排程器
- 排程器與執行緒
- 非受限排程器 vs 受限排程器
- 除錯協程與執行緒
- 在不同執行緒間跳轉
- 上下文中的任務
- 子協程
- 父協程的職責
- 命名協程以用於除錯
- 組合上下文中的元素
- 透過顯式任務取消
- 執行緒區域性資料
6. 異常處理
- 異常的傳播
- CoroutineExceptionHandler
- 取消與異常
- 異常聚合
- 監督
7. select 表示式
- 在通道中 select
- 通道關閉時 select
- Select 以傳送
- Select 延遲值
- 在延遲值通道上切換
8. 共享的可變狀態與併發
- 問題
- volatile 無濟於事
- 執行緒安全的資料結構
- 以細粒度限制執行緒
- 以粗粒度限制執行緒
- 互斥
- Actors
【 】
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70008155/viewspace-2846080/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android Kotlin協程入門AndroidKotlin
- Kotlin協程快速入門Kotlin
- Android版kotlin協程入門(四):kotlin協程開發實戰AndroidKotlin
- Android版kotlin協程入門(三):kotlin協程的異常處理AndroidKotlin
- Android版 kotlin協程入門(二):kotlin協程的關鍵知識點初步講解AndroidKotlin
- Android入門教程 | RecyclerView使用入門AndroidView
- Android Studio上Kotlin的入門AndroidKotlin
- 【Android開發入門教程】三.Activity入門指南!Android
- Kotlin 入門(一)Kotlin
- OpenGL Android課程一:入門Android
- Android入門教程 | DialogFragment 的使用AndroidFragment
- Android入門教程 | SharedPreferences 簡介Android
- Kotlin專案入門Kotlin
- Android入門教程 | EditText 使用者輸入Android
- Android入門教程 | 多執行緒Android執行緒
- Android入門教程 | Fragment 基礎概念AndroidFragment
- Android入門教程 | DrawerLayout 側滑欄Android
- Android入門教程 | RecyclerView實際使用AndroidView
- Android入門教程 | AsyncTask 使用介紹Android
- Android入門教程 | Fragment (載入方法與通訊)AndroidFragment
- git 入門教程之協同開發Git
- 詳解前端HTTP協議入門教程前端HTTP協議
- Android Kotlin 協程初探AndroidKotlin
- 新手入門,webpack入門詳細教程Web
- Android入門教程 | Button,TextView背景設定AndroidTextView
- Android入門教程 | 廣播機制 BroadcastAndroidAST
- Android入門教程:ConstraintLayout約束佈局AndroidAI
- Android OkHttp原始碼解析入門教程(一)AndroidHTTP原始碼
- Android OkHttp原始碼解析入門教程(二)AndroidHTTP原始碼
- Android Bluetooth 入門Android
- Kotlin從入門到跑路(一)Kotlin
- ZooKeeper 入門教程
- Dart 入門教程Dart
- Guzzle 入門教程
- Webpack 入門教程Web
- Ceph入門教程
- Vivado入門教程
- Elasticsearch入門教程Elasticsearch