协程三问—快手真题

2020-10-29 16:40:26 浏览数 (1)

协程,kotlin中一个神奇的组件,由于使用方便任意切换被广大开发者使用,今天就来看看协程:

  • 说说你对协程的理解
  • 说下协程具体的使用
  • 协程怎么取消

说说你对协程的理解

在我看来,协程和线程一样都是用来解决并发任务(异步任务)的方案。所以协程和线程是属于一个层级的概念,但是对于kotlin中的协程,又与广义的协程有所不同。kotlin中的协程其实是对线程的一种封装,或者说是一种线程框架,为了让异步任务更好更方便使用。

说下协程具体的使用

比如在一个异步任务需要回调到主线程的情况,普通线程需要通过handler切换线程然后进行UI更新等,一旦多个任务需要顺序调用,那更是很不方便,比如以下情况:

代码语言:javascript复制
//客户端顺序进行三次网络异步请求,并用最终结果更新UI
thread{
 iotask1(parameter) { value1 ->
  iotask1(value1) { value2 ->
   iotask1(value2) { value3 ->
    runOnUiThread{
     updateUI(value3) 
    }      
  } 
 }              
}
}

简直是魔鬼调用,如果不止3次,而是5次,6次,那还得了。。

而用协程就能很好解决这个问题:

代码语言:javascript复制
//并发请求
GlobalScope.launch(Dispatchers.Main) {
    //三次请求并发进行
 val value1 = async { request1(parameter1) }
 val value2 = async { request2(parameter2) }
 val value3 = async { request3(parameter3) }
    //所有结果全部返回后更新UI
 updateUI(value1.await(), value2.await(), value3.await())
}

//切换到io线程
suspend fun request1(parameter : Parameter){withContext(Dispatcher.IO){}}
suspend fun request2(parameter : Parameter){withContext(Dispatcher.IO){}}
suspend fun request3(parameter : Parameter){withContext(Dispatcher.IO){}}

就像是同一个线程中顺序执行的效果一样,再比如我要按顺序执行一次异步任务,然后完成后更新UI,一共三个异步任务。如果正常写应该怎么写?

代码语言:javascript复制
thread{
 iotask1() { value1 ->
  runOnUiThread{
   updateUI1(value1) 
   iotask2() { value2 ->
   runOnUiThread{
    updateUI2(value2) 
    iotask3() { value3 ->
    runOnUiThread{
     updateUI3(value3) 
    } 
       }   
   }      
   } 

  }
 }
}

晕了晕了,不就是一次异步任务,一次UI更新吗。怎么这么麻烦,来,用协程看看怎么写:

代码语言:javascript复制
    GlobalScope.launch (Dispatchers.Main) {
        ioTask1()
        ioTask1()
        ioTask1()
        updateUI1()
        updateUI2()
        updateUI3()
    }

 suspend fun ioTask1(){
        withContext(Dispatchers.IO){}
    }
    suspend fun ioTask2(){
        withContext(Dispatchers.IO){}
    }
    suspend fun ioTask3(){
        withContext(Dispatchers.IO){}
    }

    fun updateUI1(){
    }
    fun updateUI2(){
    }
    fun updateUI3(){
    }

协程怎么取消

  • 取消协程作用域将取消它的所有子协程。
代码语言:javascript复制
// 协程作用域 scope
val job1 = scope.launch { … }
val job2 = scope.launch { … }
scope.cancel()
  • 取消子协程
代码语言:javascript复制
// 协程作用域 scope
val job1 = scope.launch { … }
val job2 = scope.launch { … }
job1.cancel()

但是调用了cancel并不代表协程内的工作会马上停止,他并不会组织代码运行。比如上述的job1,正常情况处于active状态,调用了cancel方法后,协程会变成Cancelling状态,工作完成之后会变成Cancelled 状态,所以可以通过判断协程的状态来停止工作。

Jetpack 中定义的协程作用域(viewModelScope 和 lifecycleScope)可以帮助你自动取消任务,下次再详细说明,其他情况就需要自行进行绑定和取消了。


Android开发者们,快来关注公| 众 |号【码上积木】,每天三问面试题,并详细剖析,助你成为offer收割机。 积累也是一种力量。

0 人点赞