package com.example.oroutines
import kotlinx.coroutines.*
import retrofit2.Call
import retrofit2.Response
import java.lang.Exception
import java.lang.RuntimeException
import javax.security.auth.callback.Callback
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
//开启协程最简单的方式
//GlobalScope.launch每次创建的都是一个顶层协程,这种协程当应用程序结束也会更着一起结束,
// 所以可能出现协程代码块没有执行完,应用程序就结束了的情况。我们这里让主线程阻塞1s解决(如果1s运行不完还是会被kill
//fun main(){
// GlobalScope.launch {
// println("codes run in coroutine scope")
// }
// Thread.sleep(1000)
//}
//delay()函数可以让当前协程延迟置顶时间再运行,只会挂起当前协程,不影响其他协程的运行,
// 而Thread.sleep()会阻塞当前的线程,这样运行在该线程下的所有协程都会被阻塞,
// 注意delay()只能在协程的作用域或者其他挂起函数中调用。
//fun main(){
// GlobalScope.launch {
// println("codes run in coroutine scope")
// delay(1500)
// println("codes run in coroutine scope finished")
// }
// Thread.sleep(1000)
//}
//runBlocking同样会创建一个协程的作用域,但是可以保证协程作用域内所有的代码和子协程全部执行完之前一直阻塞该线程,
// runBlocking函数通常只应该在测试环境使用,在正式环境中使用容易产生性能问题。
//fun main(){
// runBlocking {
// println("codes run in coroutine scope")
// delay(1500)
// println("codes run in coroutine scope finished")
// }
//}
//launch和GlobalScope.launch函数不同,前者必须在协程的作用域中才能调用,会在当前协程作用域下创建子协程,
// 子协程特点是外层作用域协程结束了,该作用域下所有的子协程也会一同结束。而后者永远是顶层协程(顶层协程就像线程了)
//调度的过程不需要操作系统参与,这也就使得协程的并发效率出奇的高
//fun main(){
// runBlocking {
// launch {
// println("launch1")
// delay(1000)
// println("launch1")
// }
// launch {
// println("launch2")
// delay(1000)
// println("launch2")
// }
// }
//}
//随着launch函数中的逻辑越来越复杂,你可能需要将部分代码提取到一个单独的函数中,这里就有个问题:
// launch中是有协程作用域的,而单独的函数没有,那么如何调用像delay()这样的挂起函数呢?
// suspend关键字,使用它可以将任意函数声明成挂起函数,而挂起函数之间是可以相互调用的,
//suspend fun printDot(){
// println(".")
// delay(1000)
//}
//suspend只能将函数声明成挂起函数,是无法提供协程作用域的,比如现在在printDot中调用launch函数,一定无法成功,
// 这个问题可以借助coroutineScope函数来解决,coroutineScope是一个挂起函数,因此可以在其他任何挂起函数中调用,
// 它的特点是会继承外部的协程作用域并创建一个子作用域,借助这个特性,就可以给任意挂起函数提供协程作用域了。
suspend fun printDot() = coroutineScope {
launch {
println(".")
delay(1000)
}
}
//coroutineScope函数还和runBlocking函数有点相似,可以保证作用域内代码和子协程全部执行完之前一直阻塞该协程(
// 注意前者阻塞协程,后者阻塞线程,如果后者在主线程中调用可能会界面卡死,但是前者没有这种顾虑)
//fun main(){
// runBlocking {
// coroutineScope {
// launch {
// for (i in 1..10){
// println(i)
// delay(1000)
// }
// }
// }
// println("coroutineScope finished")
// }
// println("runBlocking finished")
//}
//GlobalScope.launch和runBlocking函数可以在任意位置调用,
// coroutineScope函数可以在协程作用域或挂起函数中调用,而launch只能在协程作用域中调用。
//GlobalScope.launch和launch都会返回一个job对象,只需要调用job对象的cancal()方法就可以取消协程了
//val job = Job()
//val scope = CoroutineScope(job)
//scope.launch{
// //处理具体事件的逻辑
//}
//job.cancal()
//async函数必须在协程作用域当中才能调用,会创建一个新的子协程并返回一个Deferred对象,
// 如果我们想要获取async函数代码块执行结果,可以调用Deferred的await方法。
// 调用await方法时如果代码块没有执行完,await会将当前协程阻塞,直到得到结果,
//fun main(){
// runBlocking {
// val result = async {
// 5+5
// }.await()
// println(result)
// }
//}
//fun main(){
// runBlocking {
// val start = System.currentTimeMillis()
// val result = async {
// delay(1000)
// 5+5
// }
// val result2 = async {
// delay(1000)
// 7+5
// }
// println("result is ${result.await() + result2.await()}")
// val end = System.currentTimeMillis()
// println("cost ${end -start} ms")
// }
//}
//withContext函数,类似于简化版的async,能够自动将最后一行值返回,不同的是withContext中有一个强制指定线程的参数,
// 比如Android中网络请求必须在子线程,如果在主线程中开协程去网络请求也会出错,
// Dispatchers.Default使用低并发线程策略,计算密集型任务时,开启过高的并发反而影响运行效率;
// Dispatchers.IO表示使用较高并发线程策略,执行的代码大多数时间是在阻塞和等待中,比如网络请求,可以用这个:
// Dispatchers.Main表示不会开启子线程,而是在主线程中执行代码只能在Android项目使用,kotlin程序使用会报错。
//除了coroutineScope函数,其他所有函数都是可以指定线程参数的,只不过是withContext的是强制指定的
//fun main(){
// runBlocking {
// val result = withContext(Dispatchers.Default){
// 5 +5
// }
// println(result)
// }
//}
//协程简化回调的写法,回调机制基本是靠匿名类来实现的,但是匿名类的写法比较复杂
//HttpUtil.sendHttpRequest(address,object : HttpCallbackListener{
// override fun onFinish(response : String){
// //得到服务器返回的具体内容
// }
// override fun onError(e:Exception){
// //在这里对异常情况经行处理
// }
//})
//suspendCoroutine函数必须在协程作用域或者挂起函数中才能调用,它接收一个Lambda表达式参数,
// 主要作用是将当前协程立即挂起,然后在一个普通线程中执行lambda表达式中的代码。Lambda表达式的参数列表会传入一个,
// Continuation参数,调用它的resume()方法或者rusumeWithException()可以让协程恢复执行。
//suspend fun request(adress:String):String{
// return suspendCoroutine { continuation ->
// HttpUtil.sendHttpRequest(address,object : HttpCallbackListener{
// override fun onFinish(response : String){
// //得到服务器返回的具体内容
// continuation.resume(response)
// }
// override fun onError(e:Exception){
// //在这里对异常情况经行处理
// continuation.resumeWithException(e)
// }
// })
// }
// }
//这里还不是回调了吗?哪里简化了,不过之后不管再发起多少次,就不用重复经行回调实现了,比如获取百度首页
//suspend fun getBaiduResponse(){
// try {
// val response = request("https://www.baidu.com/")
// //对服务器的相应数据进行处理
// }catch (e:Exception){
// //对异常情况进行处理
// }
//}
//suspendCoroutine函数几乎可以用来简化任何回调的写法,比如Retrofit
//val appService = ServiceCreator.create<AppService>()
//appService.getAppData().enqueue(object:Callback<List<App>>{
// override fun onResponse(call : Call<List<App>>,response:Response<List<App>>){
// //得到服务器返回数据
// }
// override fun onFailure(call : Call<List<App>>,t:Throwable){
// //处理异常
// }
//})
//由于不同的service接口返回的数据类型也不同,所以我们这次得使用泛型
suspend fun <T> Call<T>.await() : T{
return suspendCoroutine { continuation ->
enqueue(object : retrofit2.Callback<T>{
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(e)
}
override fun onResponse(call: Call<T>, response: Response<T>) {
val body = response.body()
if (body != null) continuation.resume(body)
else continuation.resumeWithException(
RuntimeException("response body is null")
)
}
})
}
}
suspend fun getAppData(){
try {
val appList = ServiceCreator.create<AppService>().getAppData().await()
//对服务器相应的数据进行处理
}catch (e:Exception){
e.printStackTrace()
}
}
Kotlin协程相关(未整理) 主要用于简化回调
最新推荐文章于 2023-10-17 18:08:44 发布