ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021-06-07

2021-06-07 10:01:43  阅读:223  来源: 互联网

标签:task1 task2 协程 07 val launch 线程 2021 06


Kotlin 协程基础Coroutine [kəruː’tiːn]

需要了解的概念,类

1.协程与线程的区别

本质上,协程是轻量级的线程

一个线程中可以有N个协程。协程中也可以有N个子协程。

2.Dispatchers类 -调度器,指定协程运行在哪个线程中

@JvmStatic //与IO共享线程池,区别在于Default限制了最大并发数,最少2个,最大为cpu的核数
public actual val Default: CoroutineDispatcher = createDefaultDispatcher()

@JvmStatic//UI线程
public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher

@JvmStatic//未定义的线程,使用这个启动的协程会立即在当前的线程执行
public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined

@JvmStatic//一个用于经常IO操作的线程池,告并行量。与Default共享线程池
public val IO: CoroutineDispatcher = DefaultScheduler.IO

3.关于Job类

协程启动后会返回一个job对象,通过此对象,可以手动控制协程的取消等操作。

cancel//取消
join//挂起,等待协程任务执行结束
cancelAndJoin() // 取消该任务并等待它结束

4.挂起函数

suspend 关键字修饰函数,只能运行在协程中。程序运行到该函数时,会被挂起直到该函数执行完成才会继续执行

构造方式

源码:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
CoroutineStart 的状态

DEFAULT//默认,立即执行,可取消

LAZY //需要手动控制start 时机

ATOMIC //This is similar to [DEFAULT], but the coroutine cannot be cancelled before it starts executing. --协程开始执行前不能取消
 
UNDISPATCHED// 立即在当前线程执行

1.GlobalScope.launch(),启动一个top-level级协程,在Android中,跟随应用的生命周期。如非必要,尽量不要使用。

fun main() {
   GlobalScope.launch(Dispathcer.Main) {
     //.....
   }
    GlobalScope.launch { // 启动一个新的协程并继续
        delay(1000L) // 非阻塞的等待 1 秒钟(默认时间单位是毫秒)
        println("World!") // 在延迟后打印输出
    }
    println("Hello,") // 协程已在等待时主线程还在继续
   job.join() //等待直到子协程执行结束 
}


2.runBlocking ,在被runBlocking修饰的函数中,只有子协程全部执行结束,函数才会结束。

fun main() = runBlocking<Unit> { // 开始执行主协程
    var job = GlobalScope.launch { // 在后台启动一个新的协程并继续
        delay(1000L)
        println("World!")
    }
    println("Hello,") // 主协程在这里会立即执行
    job.join() // 等待直到子协程执行结束 
}

3.作用域构建器

除了由不同的构建器提供协程作用域之外,还可以使用 coroutineScope 构建器声明自己的作用域。它会创建一个协程作用域并且在所有已启动子协程执行完毕之前不会结束。

fun main() = runBlocking { // this: CoroutineScope
  
    launch { //内嵌launch
        delay(200L)
        println("Task from runBlocking")
    }
    
  
  
    coroutineScope { // 创建一个协程作用域
        launch {
            delay(500L) 
            println("Task from next launch")
        }
        delay(100L)
        println("Task from coroutine scope") // 这一行会在内嵌 launch 之前输出
    }
    
  
    println("Coroutine scope is over") // 这一行在所有协程执行完毕后才输出
}
Task from coroutine scope
Task from runBlocking
Task from next launch
Coroutine scope is over

runBlockingcoroutineScope 主要区别在于,runBlocking 方法会阻塞当前线程来等待, 而 coroutineScope 只是挂起,会释放底层线程用于其他用途。 由于存在这点差异,runBlocking 是常规函数,而 coroutineScope 是挂起函数。

4.CoroutineScope(Dispatchers.Main + viewModelJob).launch

 	class MainViewModel(application: Application) : AndroidViewModel(application) {
   
    /**
     * 这是此 ViewModel 运行的所有协程所用的任务。
     * 终止这个任务将会终止此 ViewModel 开始的所有协程。
     */
    private val viewModelJob = SupervisorJob()

    /**
     * 这是 MainViewModel 启动的所有协程的主作用域。
     * 因为我们传入了 viewModelJob,可以通过调用viewModelJob.cancel() 
     * 来取消所有 uiScope 启动的协程。
     */
    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
   
     fun <T> launchUI() {
        uiScope.launch() {
           //.......省略代码
        }

    }
    
    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

AndroidX lifecycle v2.1.0 开始在 ViewModel 类中引入了扩展属性 viewModelScope。可以直接viewModelScope.launch 启动协程,不需要手动cancle。

4.withContext(Dispatcher.xxx),必须在协程体内执行,,带返回结果, 同步关系

private fun launchFromContext() {
        CoroutineScope.launch {
            val time1 = System.currentTimeMillis()
            var task1 = withContext(Dispatchers.IO) {
                delay(200)
                Log.i("kotlin", "io== ${Thread.currentThread().name}")
                1
            }
            var task2 = withContext(Dispatchers.Main) {
                delay(100)
                Log.i("kotlin", "Main== ${Thread.currentThread().name}")
                2
            }
            Log.i("kotlin", "launchFromContext end + $task1 + $task2  time==${System.currentTimeMillis() - time1}"
            )
        }
    }
launchFromContext end
io== DefaultDispatcher-worker-1
Main== main
launchFromContext end + 1 + 2  time==325

task1执行完后,再执行task2,task2执行完之后,才会执行最终的log

5.async 异步关系

  private fun launchFromAysc() {
        CoroutineScope(Dispatchers.Main).launch {
            val time1 = System.currentTimeMillis()
            val task1 = async(Dispatchers.IO) {
                Log.e("kotlin", "1.task1 start")
                delay(5000)
                Log.e("kotlin", "1.执行task1.... [当前线程为:${Thread.currentThread().name}]")
                "one"  //返回结果赋值给task1
            }

            val task2 = async(Dispatchers.IO) {
                Log.e("kotlin", "2.task2 start")
                delay(3000)
                Log.e("kotlin", "2.执行task2.... [当前线程为:${Thread.currentThread().name}]")
                "two"  //返回结果赋值给task2
            }
            Log.e("kotlin", "task1 = ${task1.await()}  , task2 = ${task2.await()} , 耗时 ${System.currentTimeMillis() - time1} ms  [当前线程为:${Thread.currentThread().name}]")
          
           Log.i("kotlin","launchFromAysc end")
        }
    }
1.task1 start]
2.task2 start]
2.执行task2.... [当前线程为:DefaultDispatcher-worker-1]
1.执行task1.... [当前线程为:DefaultDispatcher-worker-1]
task1 = one  , task2 = two , 耗时 5041 ms  [当前线程为:main]

,await是挂起函数,执行到task1.await()时,挂起,接着执行task2.await(),等task1和task2都有数据返回时,才执行最终的打印。

async 就类似于 launch。它启动了一个单独的协程,与其他协程并发工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值,而 async 返回一个 Deferred —— 一个轻量级的非阻塞 future

Android ViewModel中协程的应用

class MainViewModel(application: Application) : AndroidViewModel(application) {
    private val viewModelJob = SupervisorJob()
    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
    public var data: MutableLiveData<List<Data>> = MutableLiveData()

    fun <T> launchUI(
        block: suspend CoroutineScope.() -> Response<T>,
        one rror: (e: Throwable) -> Unit = {},
        onSuccess: (data: T) -> Unit = {},
        onComplete: () -> Unit = {}
    ) {
        uiScope.launch(CoroutineExceptionHandler { _, throwable -> one rror(throwable) }) {
            var result = block()
            if (result.errorCode == 0) {
                onSuccess(result.data)
            } else {
                one rror(Exception("返回错误码异常" + result.errorCode))
            }
            onComplete()
        }
    }

    fun test() {
        launchUI({
            Log.i("kotlin", "start" + Thread.currentThread().name)
            RetrofitUtils.getService(RequestService::class.java).getDatas().await()
        }, onSuccess = {
            Log.i("kotlin", "onSuccess" + Thread.currentThread().name)
            data.value = it
        }, one rror = {
            Log.i("kotlin", "onError" + it.message)
        }, onComplete = {
            Log.i("kotlin", "onComplete" + Thread.currentThread().name)
        })
    }


    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

标签:task1,task2,协程,07,val,launch,线程,2021,06
来源: https://blog.csdn.net/yiranhaiziqi/article/details/117650202

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有