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 –

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值