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. 在协程中进行网络操作。把结果发送出去。

参考

Android Kotlin协程入门的更多相关文章

  1. Kotlin协程入门

    开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 介绍Kotlin中的协程.用一 ...

  2. Kotlin协程基础

    开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 我们已经通过第一个例子学会了启 ...

  3. Kotlin 协程一 —— 全面了解 Kotlin 协程

    一.协程的一些前置知识 1.1 进程和线程 1.1.1基本定义 1.1.2为什么要有线程 1.1.3 进程与线程的区别 1.2 协作式与抢占式 1.2.1 协作式 1.2.2 抢占式 1.3 协程 二 ...

  4. Kotlin协程解析系列(上):协程调度与挂起

    vivo 互联网客户端团队- Ruan Wen 本文是Kotlin协程解析系列文章的开篇,主要介绍Kotlin协程的创建.协程调度与协程挂起相关的内容 一.协程引入 Kotlin 中引入 Corout ...

  5. Kotlin协程第一个示例剖析及Kotlin线程使用技巧

    Kotlin协程第一个示例剖析: 上一次https://www.cnblogs.com/webor2006/p/11712521.html已经对Kotlin中的协程有了理论化的了解了,这次则用代码来直 ...

  6. Retrofit使用Kotlin协程发送请求

    Retrofit2.6开始增加了对Kotlin协程的支持,可以通过suspend函数进行异步调用.本文简单介绍一下Retrofit中协程的使用 导入依赖 app的build文件中加入: impleme ...

  7. rxjava回调地狱-kotlin协程来帮忙

    本文探讨的是在tomcat服务端接口编程中, 异步servlet场景下( 参考我另外一个文章),用rxjava来改造接口为全流程异步方式 好处不用说 tomcat的worker线程利用率大幅提高,接口 ...

  8. Kotlin协程作用域与构建器详解

    在上次我们是通过了这种方式来创建了一个协程: 接着再来看另一种创建协程的方式: 下面用它来实现上一次程序一样的效果,先来回顾一下上一次程序的代码: 好,下面改用runBlocking的方式: 运行一下 ...

  9. Kotlin协程通信机制: Channel

    Coroutines Channels Java中的多线程通信, 总会涉及到共享状态(shared mutable state)的读写, 有同步, 死锁等问题要处理. 协程中的Channel用于协程间 ...

随机推荐

  1. Java使用Lettuce操作redis

    maven包 # 包含了lettuce jar <dependency> <groupId>org.springframework.boot</groupId> & ...

  2. C#中的集合类

    集合相当于容器,用于将一系列相似的项组合在一起. 集合可以分为泛型集合类和非泛型集合类. 多数集合类都是派生自ICollection.IComparer.IEnumerable.IList.IDict ...

  3. Qt学习笔记(2)-利用StackWidget实现选项卡式页面

    学习笔记第二篇,利用Qt实现选项卡式的页面,效果如图1.1-图1.3所示.程序实现的功能是通过点击状态栏实现不同页面的切换,实际上Qt中自带有Tab选项卡式的控件,本文利用StackWidge实现类似 ...

  4. 【转载】vim 中文帮助手册的安装

    本文出处http://hi.baidu.com/bkhcvzdvmjfkpyr/item/9c238224c1a69498b6326360 vim自带的帮助手册是英文的, 对平时编程的人来说没有多大阅 ...

  5. blog.mzywucai.club停站

    考研,不经营了,两台服务器也关了:blog.mzywucai.club也关了,就让它沉了吧!以后做个更好的?

  6. 前端云原生,以 Kubernetes 为基础设施的高可用 SSR(Vue.js) 渲染微服务初探(开源 Demo)

    背景 笔者在逛掘金的时候,有幸看到掘友狼族小狈开源的 genesis - 一个可以支持 SSR 和 CSR 渲染的微服务解决方案.总体来说思想不错,但是基于 Kubernetes 云原生部署方面一直没 ...

  7. Springboot自带定时任务实现动态配置Cron参数

    同学们,我今天分享一下SpringBoot动态配置Cron参数.场景是这样子的:后台管理界面对定时任务进行管理,可动态修改执行时间,然后保存入库,每次任务执行前从库里查询时间,以达到动态修改Cron参 ...

  8. 云原生 AI 前沿:Kubeflow Training Operator 统一云上 AI 训练

    分布式训练与 Kubeflow 当开发者想要讲深度学习的分布式训练搬上 Kubernetes 集群时,首先想到的往往就是 Kubeflow 社区中形形色色的 operators,如 tf-operat ...

  9. Mybatis(二)——全局配置文件

    一.在正文上方直接添加目录. 1.二级标题***申请开通js权限 2.添加js脚本到页脚Html代码 数组:采用一段连续的存储单元来"存储"数据.对于"指定下标" ...

  10. Flask(6)- debug 模式

    使用 Flask 开发过程中存在两个常见的问题 当 Flask 程序出错时,没有提示错误的详细信息 修改 Flask 源代码后需要重启 Flask 程序 这两个问题非常的影响开发效率,因此 Flask ...