一、前言:
线程:操作系统调度的
依附进程,在进程眼里,线程是是轻量级的
创建一万个 线程 奔溃(内存溢出)
协程:用户来控制
在线程的眼里,协程是更轻量级的
创建一万个 协程 没有任何问题
协程与线程的区别:
- 1、协程是通过编译技术实现 (不需要虚拟机 VM/操作系统 OS 的支持),通过插入相关代码来生效。与之相反,线程/进程是需要虚拟机 VM/操作系统 OS 的支持,通过调度 CPU 执行生效。
- 2、线程阻塞的代价昂贵,尤其在高负载时的可用线程很少,阻塞线程会导致一些重要任务缺少可用线程而被延迟。协程挂起几乎无代价,无需上下文切换或涉及 OS。
协程优秀博客:https://www.jianshu.com/u/a324daa6fa19
二、使用:
1、依赖:
// 协程 支持包 ------ AndroidX 扩展包
//引入协程包,里面包了core核心包
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
//不需要核心 包
//implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
//java版本的(我们一般不用)
// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-java:1.3.2'
2、阻塞式协程:
fun click1(view: View) = runBlocking { // 外协程
// 协程环境了 默认是:main线程
launch(Dispatchers.IO) { // 内协程
Log.e("click1: ", "launch ${Thread.currentThread().name}")
repeat(10) {
Thread.sleep(1000)
Log.e("click1: ", "计数中: ${it}")
}
}
}
fun click2(view: View) = runBlocking {
// 不适用协程
// displayMethod(textView)
// 使用协程
displayMethodOk(textView)
}
fun click3(view: View) = runBlocking {
// TODO 完成这种 异步线程 和 主线程 的切换, 这个需求:之前我们用RxJava实现过了哦
// 1.注册耗时操作
// 2.注册耗时操作完成后,更新注册UI
// 3.登录耗时操作
// 4.登录耗时操作完成后,更新登录UI
// main
launch {
val pro = ProgressDialog(this@MainActivity)
pro.setMessage("正在执行中...")
pro.show()
withContext(Dispatchers.IO) {
// 1.注册耗时操作 异步
Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
Thread.sleep(2000)
}
// 2.注册耗时操作完成后,更新注册UI main
Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")
withContext(Dispatchers.IO) {
// 3.登录耗时操作 异步
Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
Thread.sleep(3000)
}
// 4.登录耗时操作完成后,更新登录UI
Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")
// pro.dismiss()
}
}
displayMethodOk()调用
// =====================
fun displayMethodOk(textView: TextView) = runBlocking {
/*launch {
// main
// 默认还是 main
// Dispatchers.IO 异步
val def = async(Dispatchers.IO) {
// 异步线程
true
"String"
// 不考虑异常的情况
mOkHttpClient.newCall(mRequest).execute().body()?.string()
}
// main
// 可以拿到异步执行后的结果
textView.text = def.await()
}*/
// 下面是简化
launch {
textView.text = async(Dispatchers.IO) {
mOkHttpClient.newCall(mRequest).execute().body()?.string() // 异步的
}.await()
}
}
3、非阻塞式协程:
// 非阻塞
fun click4(view: View) {
// TODO 完成这种 异步线程 和 主线程 的切换, 这个需求:之前我们用RxJava实现过了哦
// 1.注册耗时操作
// 2.注册耗时操作完成后,更新注册UI
// 3.登录耗时操作
// 4.登录耗时操作完成后,更新登录UI
// main
GlobalScope.launch (Dispatchers.Main) {
val pro = ProgressDialog(this@MainActivity)
pro.setMessage("正在执行中...")
pro.show()
withContext(Dispatchers.IO) {
// 1.注册耗时操作 异步
Log.d("click3", "1.注册耗时操作: ${Thread.currentThread().name}")
Thread.sleep(2000)
}
// 2.注册耗时操作完成后,更新注册UI main
Log.d("click3", "2.注册耗时操作完成后,更新注册UI: ${Thread.currentThread().name}")
textView.text = "注册成功,你可以去登录了"
pro.setMessage(textView.text.toString())
withContext(Dispatchers.IO) {
// 3.登录耗时操作 异步
Log.d("click3", "3.登录耗时操作: ${Thread.currentThread().name}")
Thread.sleep(3000)
}
// 4.登录耗时操作完成后,更新登录UI
Log.d("click3", "4.登录耗时操作完成后,更新登录UI: ${Thread.currentThread().name}")
textView.text = "登录成功,欢迎回来"
pro.setMessage(textView.text.toString())
pro.dismiss()
}
}
4、非阻塞式协程取消:
// 挂起 函数 标记
suspend fun main() {
val job = GlobalScope.launch {
repeat(1000) {
delay(10)
println("111111111 $it")
}
}
println("A")
// 我只等你 100毫秒,时间到,我就结束你
Thread.sleep(100)
// job.cancel() // 一点点的时间差,不是非常
job.cancelAndJoin() // 一点点的时间差,都不允许
}
网友评论