Android 上的 Kotlin 协程(Coroutines)

官网介绍:
https://developer.android.com/kotlin/coroutines

一、协程的概念

协程(Coroutines)是一种并发设计模式,可以在 Android 平台上使用它来简化异步执行的代码。
协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念。

在 Android 上,协程有助于管理长时间运行的任务.

二、协程的特点

协程是在 Android 上进行 异步编程 的推荐解决方案。值得关注的特点包括:
(1)轻量:可以在单个线程上运行多个协程
因为协程支持挂起,不会使正在运行协程的线程阻塞
挂起比阻塞 节省内存 ,且支持多个 并行操作
(2)内存泄漏更少:使用结构化并发机制 在 一个作用域 内执行 多项操作
(3)内置取消支持:取消操作 会自动 在运行中的 整个协程层次结构 内传播。
(4)Jetpack 集成:许多 Jetpack 库 都包含提供全面 协程支持扩展
某些库还提供自己的协程作用域,可供用于结构化并发。

三、示例

1. 示例概览

实现:发出网络请求 并 将结果返回到 主线程,然后应用可以在 主线程上 向用户 显示结果。

具体而言,ViewModel 架构组件 会在 主线程 上调用 代码库层,以触发 网络请求
会介绍多种使用 协程 确保 主线程畅通的解决方案:

withContext()函数 转移线程 , 并 结合 suspend( 挂起)关键字 强制从协程里 调用.
viewModelScope.launch 启动新协程

ViewModel 包含一组可直接 与协程配合 使用的 KTX 扩展。这些扩展是 lifecycle-viewmodel-ktx 库.

2. 依赖项信息

应用的 build.gradle

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
}

3. 具体类

3.1 结果类

sealed class Result<out R> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
}

3.2 存储库类,触发 网络请求.

class LoginRepository(private val responseParser: LoginResponseParser) {
    private const val loginUrl = "https://example.com/login"
    suspend fun makeLoginRequest(
        jsonBody: String
    ): Result<LoginResponse> {

        // Move the execution of the coroutine to the I/O dispatcher
        return withContext(Dispatchers.IO) {
            // Blocking network request code
            val url = URL(loginUrl)
            (url.openConnection() as? HttpURLConnection)?.run {
                requestMethod = "POST"
                setRequestProperty("Content-Type", "application/json; utf-8")
                setRequestProperty("Accept", "application/json")
                doOutput = true
                outputStream.write(jsonBody.toByteArray())
                return Result.Success(responseParser.parse(inputStream))
            }
            return Result.Error(Exception("Cannot open HttpURLConnection"))
        }
    }
}

分析:
(1) 使用 withContext()函数将 协程的执行操作 移至其他线程( I/O 线程)
(2) suspend 关键字进行标记函数,强制从协程内调用它.

3.3 登录ViewModel, 在主线程调用 存储库 类.

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {

    fun login(username: String, token: String) {

        // Create a new coroutine on the UI thread
        viewModelScope.launch {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"

            // Make the network call and suspend execution until it finishes
            val result = loginRepository.makeLoginRequest(jsonBody)

            // Display result of the network request to the user
            when (result) {
                is Result.Success<LoginResponse> -> // Happy path
                else -> // Show error in UI
            }
        }
    }
}

分析:
(1) 应用从主线程上的 View 层调用 login() 函数。
(2) launch 在主线程上创建新协程,然后协程开始执行。
(3) 在协程内,调用 loginRepository.makeLoginRequest()
现在会挂起协程的进一步执行操作,
直至 makeLoginRequest() 中的 withContext 块结束运行。
(4) withContext 块结束运行后,
login() 中的协程在主线程上恢复执行操作,
并返回网络请求的结果。
(5) 处理 Repository 层可能抛出的异常, 使用的是 try-catch 块

4. 一些总结:

(1) viewModelScope.launch 里面调用 使用suspend 声明 且 使用了withConext()(转移到其它调度程序的某个线程的)函数.

(2) viewModelScope 与界面生命周期绑定(默认在主调度程序 Dispatchers.Main),
因此,当用户离开屏幕时,此协程启动的操作将自动取消。

(3) 当协程调用标记为 suspend 的函数时,
它不会像常规函数调用一样在函数返回之前进行阻塞,而是挂起执行,
直到结果就绪为止,然后从上次停止的位置恢复并使用返回的结果。
当它挂起并等待结果时,它会取消阻塞正在运行它的线程,以便其他函数或协程可以运行。
Kotlin编译器会把suspend 声明的函数,转换成callback形式的代码

(4) 重要提示:suspend 关键字不指定运行代码的线程。挂起函数可以在后台线程或主线程上运行。

(5) 一个协程里可以运行多个线程

(6) suspend function 的伪代码介绍


suspend function.JPG

(6) Coroutine 的基本内容(Android 官方介绍)


coroutine 内容.JPG

-- End --

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容