當(dāng)Retrofit遇上協(xié)程

Retrofit 2.6之后的版本本身支持了使用Kotlin的協(xié)程镊折。使用起來更加簡潔横浑。

在2.6之前的版本中如果要使用協(xié)程可以添加coroutines-adapter來使用儡司。例如JakeWharton大神編寫的retrofit2-kotlin-coroutines-adapter
可以看到該項目已經(jīng)標(biāo)識為DEPRECATED嘉竟。推薦升級到2.6之后的版本

2.6版本之前的寫法

接口聲明

@GET("test")
fun test() : Deferred<TestResponse>

添加adapter

Retrofit.Builder()
            .baseUrl(NetworkConfig.baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(CoroutineCallAdapterFactory.create())
            .build()

調(diào)用:

GlobalScope.launch(Dispatchers.IO){
      val response = test().await()
      ....
 }

2.6版本之后

2.6版本之后不再需要設(shè)置Adapter睦柴,直接使用Retrofit自身的方式

接口聲明

 @GET("test")
suspend fun test() : Response<TestResponse>
// 或者
 @GET("test")
suspend fun test() : Call<TestResponse>

調(diào)用

 GlobalScope.launch(Dispatchers.IO){
      try{
          val response = test()
          if(response.isSuccessful){
               ...
          }else{
              ...
          }
      }catch(e: Throwable){
           ... 
      }
 }

//Call
 GlobalScope.launch(Dispatchers.IO){
      test().enqueue(object : Callback<TestResponse>{
            override fun onFailure(call: Call<TestResponse>, t: Throwable) {
                  ...
            }
            override fun onResponse(call: Call<TestResponse>, response: Response<TestResponse>){
                ...         
            }
        }
 }

使用協(xié)程最大的好處就是可以避免回調(diào)诽凌,使異步邏輯更加簡潔,清晰坦敌。以上的寫法已經(jīng)比RxJava或其他版本要直觀了侣诵。

如果你使用了官方的MVVM架構(gòu)痢法,并且升級到了Android X,可以更加簡潔杜顺。

添加Kotlin擴(kuò)展依賴

implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-beta01'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-beta01'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-beta01'

接口聲明可以更直接

suspend fun test() : TestResponse

調(diào)用接口直接轉(zhuǎn)LiveData

 val liveData: LiveData<TestResponse> = liveData{
      val response = test()
      emit(response)
}

這樣這個LiveData就直接把接口返回的數(shù)據(jù)給接受了财搁。

狀態(tài)處理

 val liveData: LiveData<TestResponse> = liveData{
        emit(State.Loading)
        try {
            val data = test()
            emit(State.Success(data))
        }catch (e: Exception){
            emit(State.Error(e))
        }
}

ViewModelScope

ViewmModel也添加了一個擴(kuò)展ViewModelScope

viewModelScope.launch {
           val data = test()
           ...
 }

LifecycleScope

LifecycleScope是lifecycleOwner的一個擴(kuò)展。

class TestFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
               val data = test()
               ...
        }
    }
}

LifecycleScope中可以指定執(zhí)行的生命周期節(jié)點(diǎn)

lifecycleScope.launch {
        //在Activity onStart之后執(zhí)行
        whenStarted {
                val data = test()
                ...
        }
}

LiveDataScope, ViewModelScope和lifecycleScope會自動處理自身的生命周期躬络,在生命周期結(jié)束時會自動取消沒有執(zhí)行完成的協(xié)程任務(wù)尖奔,但是使用lifecycleScope應(yīng)該注意,因?yàn)閘ifecycleScope可以指定執(zhí)行的時機(jī)穷当,而在lifecycleScope一般執(zhí)行的都是異步的任務(wù)提茁,到異步任務(wù)執(zhí)行完成之后lifecycle.state是不確定的。如下面的例子:

lifecycleScope.launchWhenStarted {
            try {
                 ...
            } finally {
               ...
            }
        }

在finally中的代碼執(zhí)行時可能lifecycle.state已經(jīng)是DESTROYED膘滨,如果在執(zhí)行一些和生命周期相關(guān)的操作就需要判斷當(dāng)前的狀態(tài)甘凭。如在DESTROYED之后再執(zhí)行UI相關(guān)的操作可能會引起錯誤,甚至閃退火邓。

如果現(xiàn)在還沒升級到Android X丹弱,又使用了MVVM相關(guān)的組件,可以自己添加擴(kuò)展的形式來實(shí)現(xiàn)铲咨,如LiveData:

inline fun <T: Any> ViewModel.liveData(
        crossinline block: suspend () -> T): LiveData<State<T>>{
    val liveData = MutableLiveData<RequestResult<T>>()
    val job = CoroutineScope(context).launch {
        liveData.postValue(State.Loading)
        try {
            val value = block()
            liveData.postValue(State.Success(value))
        }catch (e: Exception){
            liveData.postValue(State.Error(e))
        }
    }
    //需要自己處理Job的生命周期
    collectJob(job)
    return liveData
}

需要注意的是要自己處理協(xié)程的生命周期躲胳,避免內(nèi)存泄漏或出現(xiàn)錯誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纤勒,一起剝皮案震驚了整個濱河市坯苹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摇天,老刑警劉巖粹湃,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泉坐,居然都是意外死亡为鳄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門腕让,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孤钦,“玉大人,你說我怎么就攤上這事纯丸∑危” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵觉鼻,是天一觀的道長俊扭。 經(jīng)常有香客問我,道長滑凉,這世上最難降的妖魔是什么统扳? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任喘帚,我火速辦了婚禮畅姊,結(jié)果婚禮上咒钟,老公的妹妹穿的比我還像新娘。我一直安慰自己若未,他們只是感情好朱嘴,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粗合,像睡著了一般萍嬉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隙疚,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天壤追,我揣著相機(jī)與錄音,去河邊找鬼供屉。 笑死行冰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伶丐。 我是一名探鬼主播悼做,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哗魂!你這毒婦竟也來了肛走?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤录别,失蹤者是張志新(化名)和其女友劉穎朽色,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體组题,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葫男,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了往踢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腾誉。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖峻呕,靈堂內(nèi)的尸體忽然破棺而出利职,到底是詐尸還是另有隱情,我是刑警寧澤瘦癌,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布猪贪,位于F島的核電站,受9級特大地震影響讯私,放射性物質(zhì)發(fā)生泄漏热押。R本人自食惡果不足惜西傀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桶癣。 院中可真熱鬧拥褂,春花似錦、人聲如沸牙寞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽间雀。三九已至悔详,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惹挟,已是汗流浹背茄螃。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留连锯,地道東北人归苍。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像萎庭,于是被迫代替她去往敵國和親霜医。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344