Android Kotlin协程入门
2021-09-26 17:09
1811 查看
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, "Unconfine ad8 d 协程 ${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.IO。
Default用的也是
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) } } }
看一下这个网络请求的流程
- 从主线程调用
reqGet()
函数 viewModelScope.launch(Dispatchers.IO)
在协程上发出网络请求- 在协程中进行网络操作。把结果发送出去。
参考
相关文章推荐
- Kotlin开发Android入门(一)
- Kotlin入门(19)Android的基础布局
- Android中使用Kotlin协程(Coroutines)和Retrofit进行网络请求(三)之异常处理与封装
- Android kotlin 协程之快速使用
- 使用LiveData和ViewModel为Android项目搭建MVVM架构(Kotlin语言版)(入门教程)
- Android Kotlin入门-类和继承
- Kotlin协程介绍和使用入门
- Kotlin从入门到放弃(三)——协程
- Kotlin Android Studio入门学习研究
- kotlin开发Android入门篇七Kotlin与Java相互调用
- Android Kotlin(一)—— Kotlin 入门与 HttpURLConnection 网络请求
- Android Kotlin入门,以及Kotlin的简单写法和监听事件。
- Kotlin Android入门学习一
- Android Studio使用Kotlin开发Android入门
- 饿了么资深Android工程师带你领略Kotlin协程的力量
- Android动画入门教程之kotlin
- 使用kotlin开发Android入门--创建项目
- Android 谷歌官方Kotlin语言入门教程(一)基础语法
- Android中使用Kotlin协程(Coroutines)和Retrofit进行网络请求(二)之文件下载
- kotlin开发Android入门篇六Lambda与高级函数