乐趣区

关于android:Android入门教程-Kotlin协程入门

Android 官网举荐应用协程来解决异步问题。

协程的特点:

  • 轻量:单个线程上可运行多个协程。协程反对挂起,不会使正在运行协程的线程阻塞。挂起比阻塞节俭内存,且反对多个并行操作。
  • 内存透露更少:应用结构化并发机制在一个作用域内执行多项操作。
  • 内置勾销反对:勾销操作会主动在运行中的整个协程层次结构内流传。
  • Jetpack 集成:许多 Jetpack 库都蕴含提供全面协程反对的扩大。某些库还提供本人的协程作用域,可用于结构化并发。
示例

首先工程中须要引入 Kotlin 与协程。而后再应用协程发动网络申请。

引入:
Android 工程中引入 Kotlin,参考 Android 我的项目应用 kotlin

有了 Kt 后,引入协程

dependencies {implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9" // 协程}

启动协程

不同于 Kotlin 工程间接应用 GlobalScope,这个示例在 ViewModel 中应用协程。须要应用viewModelScope

上面的 CorVm1 继承了 ViewModel。

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() 办法,能够看到协程是在主线程中的。

不指定 dispatcher Thread[main,5,main]

因为此协程通过 viewModelScope 启动,因而在 ViewModel 的作用域内执行。如果 ViewModel 因用户来到屏幕而被销毁,则 viewModelScope 会主动勾销,且所有运行的协程也会被勾销。

launch() 办法能够指定运行的线程。能够传入 Dispatchers 来指定运行的线程。

先简略看一下 kotlinx.coroutines 包里的 Dispatchers,它有 4 个属性:

  • Default,默认
  • Main,Android 中指定的是主线程
  • Unconfined,不指定线程
  • IO,指定 IO 线程

都通过点击事件来启动

// 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

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.IODefault 用的也是 DefaultDispatcher-worker-1 线程。

模仿网络申请

主线程中不能进行网络申请,咱们把申请放到为 IO 操作预留的线程上执行。一些信息用 MutableLiveData 收回去。

// CorVm1.kt
val info1LiveData: MutableLiveData<String> = MutableLiveData()

private fun reqGet() {
    info1LiveData.value = "发动申请"
    viewModelScope.launch(Dispatchers.IO) {val url = URL("https://www.baidu.com/s?wd=abc")
        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)
        }
    }
}

看一下这个网络申请的流程

  1. 从主线程调用 reqGet() 函数
  2. viewModelScope.launch(Dispatchers.IO)在协程上收回网络申请
  3. 在协程中进行网络操作。把后果发送进来。

kotlin 协程相干知识点

1. 协程根底

  • 你的第一个协程程序
  • 桥接阻塞与非阻塞的世界
  • 期待一个工作
  • 结构化的并发
  • 作用域构建器
  • 提取函数重构
  • ……

2. 勾销与超时

  • 勾销协程的执行
  • 勾销是合作的
  • 使计算代码可勾销
  • 在 finally 中开释资源
  • 运行不能取消的代码块
  • 超时

3. 通道

  • 通道根底
  • 敞开与迭代通道
  • 构建通道生产者
  • 管道
  • 应用管道的素数
  • 扇出
  • 扇入
  • 带缓冲的通道
  • 通道是偏心的
  • 计时器通道

4. 组合挂起函数

  • 默认顺序调用
  • 应用 async 并发
  • 惰性启动的 async
  • async 格调的函数
  • 应用 async 的结构化并发

5. 协程上下文与调度器

  • 调度器与线程
  • 非受限调度器 vs 受限调度器
  • 调试协程与线程
  • 在不同线程间跳转
  • 上下文中的工作
  • 子协程
  • 父协程的职责
  • 命名协程以用于调试
  • 组合上下文中的元素
  • 通过显式工作勾销
  • 线程部分数据

6. 异样解决

  • 异样的流传
  • CoroutineExceptionHandler
  • 勾销与异样
  • 异样聚合
  • 监督

7. select 表达式

  • 在通道中 select
  • 通道敞开时 select
  • Select 以发送
  • Select 提早值
  • 在提早值通道上切换

8. 共享的可变状态与并发

  • 问题
  • volatile 杯水车薪
  • 线程平安的数据结构
  • 以细粒度限度线程
  • 以粗粒度限度线程
  • 互斥
  • Actors

【Kotlin 入门到精通全系列视频参考】

退出移动版