Retrofit 2.6之后的版本本身支持了使用Kotlin的协程。使用起来更加简洁。
在2.6之前的版本中如果要使用协程可以添加coroutines-adapter来使用。例如JakeWharton大神编写的retrofit2-kotlin-coroutines-adapter
可以看到该项目已经标识为DEPRECATED。推荐升级到2.6之后的版本
2.6版本之前的写法
接口声明
@GET("test")
fun test() : Deferred<TestResponse>
添加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<TestResponse>
// 或者
@GET("test")
suspend fun test() : Call<TestResponse>
调用
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>){
...
}
}
}
使用协程最大的好处就是可以避免回调,使异步逻辑更加简洁,清晰。以上的写法已经比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<TestResponse> = liveData{
val response = test()
emit(response)
}
这样这个LiveData就直接把接口返回的数据给接受了。
状态处理
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也添加了一个扩展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 <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
}
需要注意的是要自己处理协程的生命周期,避免内存泄漏或出现错误。