architecture-components-samples官方示例
在协程和 Flow 使用 LiveData
本文涉及Kotlin协程,Retrofit,LiveData,ViewModel,Dagger2.Android。
在官方示例GithubBrowserSample里面没有使用协程,在实际项目里需要修改部分代码。有什么不对的地方欢迎提出。
1、Retrofit - suspend
说说这里遇到问题,加上suspend
时返回类型不能是Call<T>
或CallAdapterFactory
返回的自定义类,必须是接口返回的数据结构。下面这段代码是官方示例里面的LiveDataCallAdapterFactory
,LiveDataCallAdapter
返回一个LiveData<T>
,在CallAdapter.Factory
里面会自动加上一个Calll<T>
,返回LiveData<T>
会报类型转换异常,因为responseType
是Call<T>
并不是LiveData<T>
。
JakeWharton回复:https://github.com/square/retrofit/issues/3246
@POST(API.LOGIN)
suspend fun login(@Body any: Any): LiveData<Result<User>>
class LiveDataCallAdapterFactory : Factory() {
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<*, *>? {
if (getRawType(returnType) != LiveData::class.java) {
return null
}
val observableType = getParameterUpperBound(0, returnType as ParameterizedType)
val rawObservableType = getRawType(observableType)
if (rawObservableType != ApiResponse::class.java) {
throw IllegalArgumentException("type must be a resource")
}
if (observableType !is ParameterizedType) {
throw IllegalArgumentException("resource must be parameterized")
}
val bodyType = getParameterUpperBound(0, observableType)
return LiveDataCallAdapter<Any>(bodyType)
}
}
class LiveDataCallAdapter<R>(private val responseType: Type) :
CallAdapter<R, LiveData<ApiResponse<R>>> {
override fun responseType() = responseType
override fun adapt(call: Call<R>): LiveData<ApiResponse<R>> {
return object : LiveData<ApiResponse<R>>() {
private var started = AtomicBoolean(false)
override fun onActive() {
super.onActive()
if (started.compareAndSet(false, true)) {
call.enqueue(object : Callback<R> {
override fun onResponse(call: Call<R>, response: Response<R>) {
postValue(ApiResponse.create(response))
}
override fun onFailure(call: Call<R>, throwable: Throwable) {
postValue(ApiResponse.create(throwable))
}
})
}
}
}
}
}
换成Call<T>
会导致GsonConverterFactory
报错。
@POST(API.LOGIN)
suspend fun login(@Body any: Any): Call<Result<User>>