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

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的情况下可以少写很多线程的创建、切换、异步接口的回调。让代码更加干净清爽。
个人学习笔记,如有错误不对的地方欢迎各位大佬指出。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容