美文网首页Coroutine(协程)
Kotlin—Coroutine(协程)的基本使用

Kotlin—Coroutine(协程)的基本使用

作者: 烫烫琨烫烫烫烫琨烫烫 | 来源:发表于2019-08-12 22:11 被阅读0次

Kotlin—Coroutine(协程)的基本使用

什么是协程

在java中异步都会使用到线程,在kotlin中引入了协程的概念。与线程类似,协程也是用于处理异步的,不过与线程相比更加轻巧。协程完全通过编译技术实现,使用挂起机制来实现异步,而不会阻塞线程。协程是一种避免线程阻塞、开销更小且更加可控的异步操作

协程的基础使用

创建协程,有三种方式runBlockinglaunchasync

  • runBlocking 创建一个阻塞的协程,当协程内部代码执行完毕后才会执行后面的代码。

    fun main() {
        println("Hello")
        runBlocking {
            delay(1000)
            println("World")
        }
        println("---end---")
    }
    

    runBlocking 创建的协程里面,调用 delay让此协程挂起1秒。执行代码,首先打印Hello,1秒后打印World,最后打印—end—。注意delay挂起函数只有在协程内部才能调用

  • launch 在当前协程作用域下面创建一个非阻塞子协程,同时返回个 Job 对象,用来控制当前协程。

    fun main() = runBlocking {
        println("hello")
        launch {
            delay(1000)
            println("world")
        }
        println("---end---")
    }
    

    使用 runBlocking 来包裹 main 函数,函数整体都处于runBlocking创建的协程作用域下面,然后通过launch 创建一个子协程,挂起1秒之后打印输出。执行代码发现首先输出hello和—end—,等待一秒之后打印world,如何让他按顺序执行。

    fun main() = runBlocking {
        println("hello")
        val job = launch {
            delay(1000)
            println("world")
        }
        job.join()
        println("---end---")
    }
    

    修改代码,拿到 launch 返回的job对象,调用 join() 函数,此时会等待job协程内部的代码执行完毕后才会往后执行。执行代码,先打印hello,然后1秒后打印world和—end—。

  • Job 常用方法

    • isActive
    • isCompleted
    • isCanceledstart
    • cancel
    • join
  • GlobalScope.launch 创建一个全局非阻塞协程,

    fun main() {
        println("hello")
        GlobalScope.launch {
              delay(1000)
            println("world")
        }
        Thread.sleep(1500)
        println("---end---")
    }
    

    使用 GlobalScope.launch 在任何地方都能创建一个全局的协程,由于 launch 创建的协程是非阻塞的,所以让当前线程睡眠1.5秒等待协程执行完毕。与上面代码打印结果一样。由于使用 GlobalScope.launch 时,会创建一个顶层协程。虽然很轻量,但它运行时仍会消耗一些内存资源,所以通常是在协程内部作用域下使用launch创建协程,而不是使用GlobalScope来创建全局协程。

  • async 创建一个非阻塞协程,同时返回Deferred ,可通过 await() 函数获取协程返回的具体值;

    fun main() = runBlocking {
        println("hello")
        val def = async {
            delay(1000)
            "world"
        }
        println(def.await())
        println("---end---")
    }
    
  • 挂起函数

    接着上面例子,将 launch 协程内部的代码封装为一个函数,使用suspend关键,这个函数就叫 挂起函数,上面的 delay 就是一个封装好的挂起函数。

    fun main() = runBlocking {
        println("hello")
        val job = launch {
            delay1000()
        }
        job.join()
        println("---end---")
    }
    
     suspend fun delay1000(){
        delay(1000)
        println("world")
    }
    
  • 调度器

    上面提到三种创建协程的方式都有一个选填参数 CoroutineContext,协程的上下文环境。也就是协程调度器,调度器确定了协程执行的线程环境。

    • Dispatchers.Default 默认后台线程池里的线程 ;
    • Dispatchers.Main Android主线程;
    • Dispatchers.IO 后台线程池里的IO线程 ;
    • Dispatchers.Unconfined 不限制,使用父协程所属的线程;
    • newSingleThreadContext 使用新的线程。

    如需要在协程中切换调度器可使用withContextwithContext返回最后一行代码的返回值。

  • Android中的使用

    简单了介绍了协程的基本使用,写个小demo,模拟网络请求然后再界面展示数据。在activity中首先要实现CoroutineScope 接口,然后通过by关键字将接口的具体实现委托给 MainScope,这样当前activity就是一个协程作用域了。

    class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            button.setOnClickListener {
                showData()
            }
        }
      // 创建协程,默认在当前线程,也就是UI线程
        private fun showData() = launch {
            progress.visibility = View.VISIBLE
            textView.text = loadData()
            progress.visibility = View.GONE
        }
    
      //网络请求 切换为IO线程
        private suspend fun loadData()= withContext(Dispatchers.IO) {
            delay(2000)//挂起2秒 模拟网络请求
            "假装这是网络请求到的数据" //返回请求到的数据
        }
    }
    

基本介绍完了协程的最最最基础的使用,相比于线程除了内存开销更小、不会造成线程阻塞的优点之外之外,个人觉得在没有用RxJava的情况下可以少写很多线程的创建、切换、异步接口的回调。让代码更加干净清爽。
个人学习笔记,如有错误不对的地方欢迎各位大佬指出。

相关文章

网友评论

    本文标题:Kotlin—Coroutine(协程)的基本使用

    本文链接:https://www.haomeiwen.com/subject/vkopjctx.html