kotlin協程一 :kotlin協程介紹以及android中簡單使用

參考文章:

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部分源碼進行分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章