# kotlin-coroutine-demo
* 下方对kotlin协程的原理进行的分析
* 感觉有点长,还有点杂,后面有时间再整理一下
## demo说明
kotlin协程demo,kotlin coroutine + mvvm + okhttp,内部提供mvc与mvvm的不同实现,换下主活动在打包即可
* 界面如下,点击按钮开始进行网络请求,同时,改变button状态,为倒计时效果,button下方的数据也开始递增
![Screenshot_2021-04-02-14-09-22-796_com.example.ko](Screenshot_2021-04-02-14-09-22-796_com.example.ko.jpg)
![Screenshot_2021-04-02-14-09-30-279_com.example.ko](Screenshot_2021-04-02-14-09-30-279_com.example.ko.jpg)
---
# Kotlin协程
* [参考官网](https://docs.gradle.org/current/userguide/what_is_gradle.html),后期如果api有变动也参考官网
* **这里只对结构性的东西进行记录**
* 额外话题:直接都没有用过debug打断点来跟源码,现在用了,除了走错之后需要重来之外,真香
## 基础
* 协程(框架)其实就是一套由kotlin官方提供的线程API,一个线程框架
* 协程并不是一个轻量级的线程,而是很像一个轻量级的线程
* 现在写完这篇文章之后,我理解:协程(本身)就是一个lambda参数里的逻辑,一段可以挂起和恢复执行的运算逻辑(ps:本文中很多地方使用lambda参数来表示协程)
* 优点:方便,能在同一个代码块里进行多次线程切换,代替了多次的回调,使用看似同步的代码实现了异步的效果
* 在性能上,使用自旋代替了线程阻塞
```
// 使用下面的异常捕获器与网络请求函数
launch(exceptionHandler) {
contentTextView?.text = withContext(Dispatchers.IO) {
loadDataByCoroutine()
}
}
// 定义异常捕获器
private val exceptionHandler by lazy {
CoroutineExceptionHandler { _, throwable ->
LogUtil.log("网络请求发生错误:${throwable.message}")
contentTextView?.text = "网络请求发生错误,请检查网络连接"
}
}
// 使用协程进行网络请求
private suspend fun loadDataByCoroutine() = suspendCoroutine<String> { con ->
// 请求数据并返回,wan-android url: https://wanandroid.com/wxarticle/chapters/json
LogUtil.log("load Data " + Thread.currentThread().name)
val okHttpClient = OkHttpClient()
val request = Request.Builder()
.url("https://wanandroid.com/wxarticle/chapters/json")
.get()
.build()
val call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
con.resumeWithException(e) // 恢复协程,并带有一个异常
}
override fun onResponse(call: Call, response: Response) {
con.resume(response.body().string()) // 恢复协程,并带有一个结果
}
})
}
```
* 非阻塞式挂起,非阻塞指的是不阻塞线程,挂起是只挂起协程,其实多线程也是非阻塞式的
* 应用场景:解决回调地狱问题、预防ANR问题、自动切换线程、并发不会阻塞线程(用户态 -> 内核态的切换,性能消耗比较大)
## 协程的构建
* Gradle引入协程依赖
```
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M2' //kotlin协程核心库
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0' //android需要添加
```
* 我了解到6种创建方式(两种全局:`GlobalScope.launch {...}`、`GlobalScope.async {...}`)
* 下面的构建函数都是`CoroutineScope`的扩展函数,继承了当前CoroutineScope的CoroutineContext和取消操作
* 可以在context位置使用`CoroutineName("test coroutine 1")`指定名字
* 打印协程名字,需要设置JVM启动参数:-Dkotlinx.coroutines.debug
* 这样在代码跑起来的时候,在打印Thread的name的时候,就会自动带上协程的名字
* 当然,也通可以通过`coroutineContext[CoroutineName]`拿到这个协程的名字,直接输出
* 协程构建器分为两类:自动传播异常的(launch、actor)、向用户暴露异常的(async、produce)。这里不作介绍,具体在异常那块有讲解
* **launch函数**
* 启动一个协程,不会阻塞当前线程。返回一个 `Job`,可以用于协程的取消等操作
- 在 `GlobalScope`类与 `CoroutineScope` 类中都存在 `launch` 函数。前者为全局范围的,且不存在父协程,并且除非执行完,或者手动取消,该协程都将一直运行,所以建议少用。后者范围是创建它的父协程
- `laucnch` 函数有三个参数:`CoroutineContext`、`CoroutineStart`、`block Lambda`
```
//GlobalScope的用法也是类似的,不过不能指定coroutineContext
CoroutineScope(Dispatchers.Default).launch {
Log.d("MainActivity", "new Coroutines")
}
Log.d("MainActivity", "Main Thread")
```
* **actor函数**
* 创建一个协程,返回一个通道:`SendChannel`,可用于向协程中发送数据,lambda表示式:接收者类型是`ActorScope`,该接口中提供一个`channel`常量,用于接收其他地方向协程通道中发来的数据
```
fun main() = runBlocking {
var actor = actor<Int> {
for (i in channel) {
print(i)
}
}
repeat(23) {
actor.send(it)
}
}
```
* **async函数**
- 创建一个协程,返回一个 `Deferred`对象,可用于协程的取消等操作
- 该函数跟`launch()`函数几乎是一摸一样的(在`GlobalScope`中也有),唯一的不同点在于 block lambda这个函数式参数的返回值
- `launch()`函数直接返回Unit
- `async()`函数返回一个类型参数T(out位置),这个参数会作为Deferred类中函数的返回值
````
fun main() = runBlocking {
val deferred = async() {
repeat(3) {
println("1")
}
"result"
}
println(deferred.await()) //log:result
}
````
* **produce函数**
* 创建一个新的协程,返回一个通道:ReceiveChannel,可用于接收协程中发出的数据;lambda表示式:接收者类型是`ProducerScope`,该接口中提供一个`channel`常量,用于该协程向外界发送数据
```
fun main() = runBlocking {
val receiveChannel = produce<Int> {
repeat(5) {
channel.send(it)
}
}
repeat(5) {
println(receiveChannel.receive())
}
}
```
* **runBlocking函数**
* 创建一个新的协程,并阻塞当前线程直到协程结束,返回lambda表达式最后一行
- 该函数主要用于 `main` 函数测试、桥接协程( `suspend` 函数只能协程或 `suspend` 函数中调用,使用该函数来创建一个可以调用 `suspend` 函数的作用域)
```
//作为桥接协程使用
runBlocking {
Log.d("MainActivity", "delay 1s") //打印顺序:1
delay(1000)
Log.d("MainActivity", "start new Coroutines") //打印顺序:2
launch {
Log.d("MainActivity", "delay 1s") //打印顺序:4
delay(1000)
Log.d("MainActivity", "another new Coroutines") //打印顺序:5
}
Log.d("MainActivity", "new Coroutines") //打印顺序:3
}
Log.d("MainActivity", "Main Thread") //打印顺序:6
```
* 阻塞线程、不阻塞线程
* runBlocking函数会阻塞线程,通过无限循环`while(true`,并通过LockSupport.park()上锁
```
// joinBlocking函数
while (true) {
@Suppress("DEPRECATION")
if (Thread.interrupted()) throw InterruptedException().also { cancelCoroutine(it) }
val parkNanos = eventLoop?.processNextEvent() ?: Long.MAX_VALUE
// note: process next even may loose unpark flag, so check if completed before parking
没有合适的资源?快使用搜索试试~ 我知道了~
kotlin-coroutine-demo:kotlin协程demo,kotlin协程+ mvvm + okhttp
共59个文件
xml:20个
png:10个
kt:9个
5星 · 超过95%的资源 需积分: 46 5 下载量 82 浏览量
2021-04-02
14:23:02
上传
评论
收藏 9.82MB ZIP 举报
温馨提示
Kotlin协程演示 下方对kotlin协程的原理进行的分析感觉有点长,还有点杂,后面有时间再整理一下 演示说明 kotlin协程演示,kotlin协程+ mvvm + okhttp,内部提供mvc与mvvm的不同实现,换下主活动在打包即可 界面如下,点击按钮开始进行网络请求,同时,更改按钮状态,为倒计时效果,按钮下方的数据也开始递增 Kotlin协程 ,后续如果api有变动也参考官网 这里只对结构性的东西进行记录额外主题:直接都没有用过debug打断点来跟原始码,现在用了,除了走错之后需要重来之外,真香 基础 协程(框架)其实就是一套由kotlin官方提供的线程API,一个线程框架 协程并非一个轻量级的线程,或者很像一个轻量级的线程 现在写完这篇文章之后,我理解:协程(本身)就是一个lambda参数里的逻辑,一段可以挂起并恢复执行的运算逻辑(ps:此处中很多地方使用lambda参数来表示
资源详情
资源评论
资源推荐
收起资源包目录
kotlin-coroutine-demo-master.zip (59个子文件)
kotlin-coroutine-demo-master
Screenshot_2021-04-02-14-09-22-796_com.example.ko.jpg 89KB
app
.gitignore 6B
build.gradle 2KB
src
androidTest
java
com
example
kotlintestdemo
ExampleInstrumentedTest.kt 679B
main
AndroidManifest.xml 957B
res
mipmap-xhdpi
ic_launcher_round.png 7KB
ic_launcher.png 5KB
mipmap-mdpi
ic_launcher_round.png 3KB
ic_launcher.png 3KB
layout
activity_main.xml 784B
activity_show_text.xml 1KB
mipmap-xxhdpi
ic_launcher_round.png 12KB
ic_launcher.png 8KB
drawable
ic_launcher_background.xml 5KB
mipmap-anydpi-v26
ic_launcher_round.xml 272B
ic_launcher.xml 272B
drawable-v24
ic_launcher_foreground.xml 2KB
mipmap-hdpi
ic_launcher_round.png 5KB
ic_launcher.png 4KB
mipmap-xxxhdpi
ic_launcher_round.png 16KB
ic_launcher.png 10KB
values-night
themes.xml 836B
values
strings.xml 76B
colors.xml 378B
themes.xml 836B
java
com
example
kotlintestdemo
MainActivity.kt 4KB
LogUtil.kt 201B
Test.kt 378B
mvvm
TextViewModel.kt 3KB
ShowTextActivity.kt 2KB
NetUtil.kt 2KB
Repository.kt 862B
Test.java 190B
test
java
com
example
kotlintestdemo
ExampleUnitTest.kt 350B
proguard-rules.pro 750B
settings.gradle 50B
build.gradle 660B
Screenshot_2021-04-02-14-09-30-279_com.example.ko.jpg 676KB
build
intermediates
lint-cache
sdk-registry.xml
sdk-registry.xml 23KB
api-versions-0-30.0.5.bin 7.89MB
typos-en.txt-2.bin 101KB
maven.google
com
google
android
material
group-index.xml 875B
master-index.xml 5KB
org
jetbrains
kotlin
group-index.xml 1001B
androidx
core
group-index.xml 1KB
constraintlayout
group-index.xml 859B
appcompat
group-index.xml 665B
test
ext
group-index.xml 1KB
espresso
group-index.xml 3KB
gradlew 6KB
.DS_Store 10KB
README.md 69KB
gradlew.bat 3KB
gradle.properties 1KB
bugreport-dipper-PKQ1.180729.001-2020-12-16-17-54-49.zip 7.31MB
gradle
wrapper
gradle-wrapper.properties 200B
gradle-wrapper.jar 58KB
dependencies.txt 127KB
local.properties 438B
共 59 条
- 1
123你走吧你走吧
- 粉丝: 41
- 资源: 4614
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论1