当Retrofit遇上协程

Retrofit 2.6之后的版本本身支持了使用Kotlin的协程。使用起来更加简洁。

在2.6之前的版本中如果要使用协程可以添加coroutines-adapter来使用。例如JakeWharton大神编写的retrofit2-kotlin-coroutines-adapter
可以看到该项目已经标识为DEPRECATED。推荐升级到2.6之后的版本

2.6版本之前的写法

接口声明

@GET("test")
fun test() : Deferred

添加adapter

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

调用:

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

2.6版本之后

2.6版本之后不再需要设置Adapter,直接使用Retrofit自身的方式

接口声明

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

调用

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

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

使用协程最大的好处就是可以避免回调,使异步逻辑更加简洁,清晰。以上的写法已经比RxJava或其他版本要直观了。

如果你使用了官方的MVVM架构,并且升级到了Android X,可以更加简洁。

添加Kotlin扩展依赖

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

调用接口直接转LiveData

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

这样这个LiveData就直接把接口返回的数据给接受了。

状态处理

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

ViewModelScope

ViewmModel也添加了一个扩展ViewModelScope

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

LifecycleScope

LifecycleScope是lifecycleOwner的一个扩展。

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

LifecycleScope中可以指定执行的生命周期节点

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

LiveDataScope, ViewModelScope和lifecycleScope会自动处理自身的生命周期,在生命周期结束时会自动取消没有执行完成的协程任务,但是使用lifecycleScope应该注意,因为lifecycleScope可以指定执行的时机,而在lifecycleScope一般执行的都是异步的任务,到异步任务执行完成之后lifecycle.state是不确定的。如下面的例子:

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

在finally中的代码执行时可能lifecycle.state已经是DESTROYED,如果在执行一些和生命周期相关的操作就需要判断当前的状态。如在DESTROYED之后再执行UI相关的操作可能会引起错误,甚至闪退。

如果现在还没升级到Android X,又使用了MVVM相关的组件,可以自己添加扩展的形式来实现,如LiveData:

inline fun  ViewModel.liveData(
        crossinline block: suspend () -> T): LiveData>{
    val liveData = MutableLiveData>()
    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
}

需要注意的是要自己处理协程的生命周期,避免内存泄漏或出现错误。

你可能感兴趣的:(当Retrofit遇上协程)