天天看点

kotlin协程一 :kotlin协程介绍以及android中简单使用在kotlin中协程的概念kotlin常用apiRetrofit+RxJava与Retrofit+coroutine对比:

参考文章:

https://kaixue.io/kotlin-coroutines-1/

https://johnnyshieh.me/posts/kotlin-coroutine-introduction/

在kotlin中协程的概念

kotlin协程这个概念不是一天两天提出的了,有兴趣想学一学,但是在网上你可能会看到很多非常专业的术语:

协程和线程类似;就像一种轻量级的线程;是协作式的,不需要线程的同步操作;协程是用户态的,他的切换不需要和操作系统交互............

等等一些话。

讲道理,看完这些话仿佛看到了一个超越自己认知的新东西,这些话在其他的语言中可能是对的,但是和kotlin中的协程概念不同:

kotlin协程是一个官方提供的线程调度的api,使用kotlin协程,可以用看似同步的方式,写出异步的代码。

kotlin常用api

CoroutineScope:协程对象本身,可直接通过CoroutineScope构造方法new对象,或使用GlobalScope全局协程对象,或继承自定义CoroutineScope(库中提供了CoroutineScope的实现类,在之后有介绍)

CoroutineContext:协程上下文,主要由协程的Job和CoroutineDispatcher组成;CoroutineContext作为CoroutineScope的参数使用。

CoroutineDispatcher:协程调度器,通过该变量可指定协程所运行的线程。

Dispatchers.Main //指定任务运行在主线程
Dispatchers.IO //指定任务运行在子线程,例如网络请求,文件读取
Dispatchers.Default //未指定Dispatchers时,有JVM的共享线程池支持
           

创建协程常用的方法主要有launch和async(runBlocking官方注释中说道该方法会阻塞当前线程,直到使用runBlocking启动的协程运行结束才会恢复当前线程,一般用于main方法和test测试中,之后就不提他的使用了)

使用launch手动创建一个协程:

CoroutineScope(Dispatchers.Main).launch { //new CoroutineScope对象,并创建协程

}
        
GlobalScope.launch { //使用GlobalScop创建协程
            
}

MainScope().launch { //CoroutineScope子类MainScope, 默认运行在主线程中,创建协程
            
}
           

使用async创建一个协程:

val deferred = MainScope().async {

}
           

使用async方法创建协程会返回一个deferred对象,通过deferred.await()挂起函数,可以得到异步获取的值。

Retrofit+RxJava与Retrofit+coroutine对比:

下面通过一个简单的例子对将coroutine和rxjava作对比:

使用retrofit+rxjava:

interface ApiService {

    @GET("/users.json")
    fun getUsers(): Observable<MainUserResult>

}
           
class MainAct : AppCompatActivity() {

    @Inject lateinit var apiService: ApiService
    
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    private fun getUsersData() {
      
       apiService.getUsers()
           .subscribeOn(Schedulers.io())
           .observeOn(AndroidSchedulers.mainThread())
           .subscribe ({

           })
    }
}
           

retrofit+coroutine:

@GET("/users.json")
fun getUsers(): Call<MainUserResult>


///

class MainAct : AppCompatActivity(),
    CoroutineScope by MainScope() {

    @Inject lateinit var apiService: ApiService
    

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    private fun getUsersData() {
       launch(Dispatchers.Main) {
           val result = apiService.getUsers().await()
       }
    }
}
           

我使用kotlin委托的方式, 让MainActivity实现CoroutineScope接口,并委托给MainScope,这样就可以在MainActivity中直接使用launch,而不需要每次都构建CoroutineScope对象了。而retrofit的Call对象,对coronutine有支持,提供了挂起方法await:

suspend fun <T : Any> Call<T>.await(): T {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        if (response.isSuccessful) {
          val body = response.body()
          if (body == null) {
            //.....
          } else {
            continuation.resume(body)
          }
        } else {
          continuation.resumeWithException(HttpException(response))
        }
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}
           

有时候可能我们需要两个api同时请求,同时获取结果,在RxJava中我们使用zip表达式实现该功能,在retrofit + coroutine中可以直接调用await方法,就可以实现:

launch(Dispatchers.Main) {
    val userResult = apiService.getUsers().await()
    val user = apiService.getUser("1111").await()
    handleData(userResult, user)
}
           

下一篇会对kotlin coroutine异常处理,以及coroutine部分源码进行分析。