1.?Kotlin 協程的核心概念
1.1 協程(Coroutine)
- 定義:協程是一種輕量級的執行上下文,可以在任何時候掛起和恢復,而不需要阻塞線程。
- 特點:
- 比傳統線程更輕量,開銷更小。
- 支持掛起和恢復,避免了阻塞線程和資源浪費。
- 提供更簡潔的并發編程方式。
1.2 掛起函數(Suspend Function)
- 定義:使用?
suspend
?關鍵字修飾的函數,可以在協程中掛起執行,掛起期間不會阻塞線程。 - 作用:允許協程在等待任務完成時釋放線程資源,待任務完成后恢復執行。
1.3 協程作用域(Coroutine Scope)
- 定義:協程作用域定義了協程的生命周期,確保協程在作用域結束時被取消。
- 常見作用域:
GlobalScope
:全局作用域,生命周期與整個應用程序一致(不推薦用于實際開發)。CoroutineScope
:自定義作用域,可通過?CoroutineScope(Dispatchers)
?創建。runBlocking
:用于測試場景,會阻塞當前線程直到協程完成。
1.4 協程構建器(Coroutine Builders)
- launch:啟動一個協程,不返回結果。
- async:啟動一個協程,并返回一個?
Deferred
?對象,可用于獲取結果。 - runBlocking:阻塞當前線程,直到協程完成(僅用于測試)。
2.?Kotlin 協程的使用方法
以下是協程使用的基本步驟:
2.1 添加依賴項
在項目的?build.gradle
?文件中添加 Kotlin 協程庫依賴:
dependencies {implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
}
2.2 創建協程作用域
協程必須在協程作用域中運行。例如:
import kotlinx.coroutines.*fun main() = runBlocking { // 用于測試,實際開發中避免使用val scope = CoroutineScope(Dispatchers.Default)scope.launch {// 在這里執行異步任務}
}
2.3 啟動協程
使用?launch
?或?async
?啟動協程:
- launch:用于不需要返回結果的異步任務。
- async:用于需要返回結果的異步任務。
scope.launch {delay(1000L) // 模擬耗時操作println("異步任務完成")
}val deferred = scope.async {delay(1000L)"異步任務結果"
}
println("異步任務返回值: ${deferred.await()}")
2.4 使用掛起函數
掛起函數允許協程在等待任務時掛起,例如?delay
:
suspend fun fetchData(): String {delay(1000L) // 模擬網絡請求return "Data fetched"
}
3.?Kotlin 協程的具體示例
以下通過幾個常見場景展示協程的實際用法。
3.1 簡單的異步任務
使用?launch
?啟動一個異步任務:
import kotlinx.coroutines.*fun main() = runBlocking {launch {delay(1000L)println("World!")}println("Hello,")
}輸出:
Hello,
World!
3.2 并行任務與結果獲取
使用?async
?和?await
?實現并行任務:
import kotlinx.coroutines.*fun main() = runBlocking {val deferred1 = async {fetchDataFromNetwork1()}val deferred2 = async {fetchDataFromNetwork2()}println("Data1: ${deferred1.await()}")println("Data2: ${deferred2.await()}")
}suspend fun fetchDataFromNetwork1(): String {delay(1000L)return "NetworkData1"
}suspend fun fetchDataFromNetwork2(): String {delay(1000L)return "NetworkData2"
}
3.3?取消協程
使用?cancel
?方法取消協程:
import kotlinx.coroutines.*fun main() = runBlocking {val job = launch {delay(5000L)println("Task completed")}delay(1000L)job.cancel()println("Coroutine cancelled")
}
4.實際應用示例
網絡請求與數據庫操作
// 假設有以下掛起函數
suspend fun fetchUserData(): UserData = withContext(Dispatchers.IO) {// 模擬網絡請求delay(1000)UserData("John", 30)
}suspend fun saveToDatabase(user: UserData) = withContext(Dispatchers.IO) {// 模擬數據庫操作delay(500)println("User saved: $user")
}data class UserData(val name: String, val age: Int)fun main() = runBlocking {// 順序執行val user = fetchUserData()saveToDatabase(user)// 并發執行多個網絡請求val users = listOf("user1", "user2", "user3")val deferredList = users.map { userId ->async { fetchUserDataForId(userId) }}val results = deferredList.awaitAll()println("All users fetched: $results")
}suspend fun fetchUserDataForId(userId: String): UserData {delay(1000)return UserData("$userId-Name", 20 + userId.last().digitToInt())
}
5.?總結
- 核心概念:協程、掛起函數、協程作用域和協程構建器是協程編程的基礎。
- 使用方法:通過添加依賴、創建作用域、啟動協程和使用掛起函數,可以輕松實現異步編程。
- 適用場景:協程適用于網絡請求、文件 IO、CPU 密集型任務等需要并發處理的場景。