我使用LiveData调用适配器进行改型,改编自Google示例
public interface ApiService {
@GET("?schema=1.2&form=cjson&byCategories=liveChannels&range=1-500&count=true")
LiveData<ApiResponse<Page<Media>>> getChannels();
}
我必须使用不同的终结点,因此我想使ApiResponse通用。
ApiResponse将是接口(interface)或抽象的,并且对于所有这些端点都具有不同的变体。
我不想为扩展ApiResponse的每个类编写不同的LiveData扩展。
我想做类似的事情:
RetrofitLiveData<R, E extends ApiResponse<R>> extends LiveData<E<R>>
(我知道之前的代码不可编译,只是我想要的示例)
然后在改造界面中,我可以:
LiveData<Endpoint1ApiResponse<Endpoint1Data>>
LiveData<Endpoint2ApiResponse<Endpoint2Data>>
LiveData<Endpoint3ApiResponse<Endpoint3Data>>
public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter<?, ?> get(@NonNull Type returnType, @NonNull Annotation[] annotations,
@NonNull Retrofit retrofit) {
if (getRawType(returnType) != LiveData.class) {
return null;
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType != ApiResponse.class) {
throw new IllegalArgumentException("type must be a resource");
}
if (! (observableType instanceof ParameterizedType)) {
throw new IllegalArgumentException("resource must be parameterized");
}
Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new LiveDataCallAdapter<>(bodyType);
}
}
public class LiveDataCallAdapter<R> implements CallAdapter<R, LiveData<ApiResponse<R>>> {
private final Type responseType;
public LiveDataCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override
public Type responseType() {
return responseType;
}
@Override
public LiveData<ApiResponse<R>> adapt(@NonNull Call<R> call) {
return new RetrofitLiveData<R>(call);
}
}
public class RetrofitLiveData<R> extends LiveData<ApiResponse<R>> {
private final Call<R> call;
public RetrofitLiveData(Call<R> call) {
this.call = call;
}
@Override
protected void onActive() {
if (!call.isCanceled() && !call.isExecuted()) {
call.enqueue(callback);
}
}
private final Callback<R> callback = new Callback<R>() {
@Override
public void onResponse(@NonNull Call<R> call, @NonNull Response<R> response) {
postValue(new ApiResponse<>(response));
}
@Override
public void onFailure(@NonNull Call<R> call, @NonNull Throwable t) {
postValue(new ApiResponse<>(t));
}
};
public void cancel() {
if (!call.isCanceled()) {
call.cancel();
}
}
}
public class ApiResponse<T> {
public final int code;
@Nullable
public final T body;
@Nullable
public final String errorMessage;
public ApiResponse(Throwable error) {
code = 500;
body = null;
errorMessage = error.getMessage();
}
public ApiResponse(Response<T> response) {
// .......... not important here
}
public boolean isSuccessful() {
return code >= 200 && code < 300;
}
}
最佳答案
您可以使用这些类来实现您的目标。
1-您需要在CallAdapterFactory中使用liveDataWrapper才能使用它。如果您需要其他类型的事件,则可以在NetworkData密封类中添加它,并在所需部分中使用它
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.MutableLiveData
import retrofit2.HttpException
class NetworkLiveData<T> : MutableLiveData<NetworkLiveData.NetworkData<T?>>() {
private lateinit var observer: NetworkData<T?>.() -> Unit
internal fun onSuccessResponse(body: T?) {
val result = NetworkData.Success(body)
postValue(result)
}
fun observeForever(f: NetworkData<T?>.() -> Unit) {
observer = f
super.observeForever(f)
}
internal fun onResponseHttpException(httpException: HttpException) {
val result = NetworkData.ErrorResponse<T?>(httpException)
postValue(result)
}
internal fun onFailedRequest(t: Throwable) {
val result = NetworkData.ErrorRequest<T?>(t)
postValue(result)
}
fun onFinish() {
Handler(Looper.getMainLooper()).post {
this.removeObserver(observer)
}
}
sealed class NetworkData<T> {
data class Success<T>(val value: T) : NetworkData<T>()
data class ErrorResponse<T>(val httpException: HttpException) : NetworkData<T>()
data class ErrorRequest<T>(val t: Throwable) : NetworkData<T>()
fun onSuccess(f: (responseBody: T) -> Unit) {
if (this is Success) {
f.invoke(value)
}
}
fun onHttpException(f: (code: Int, message: String) -> Unit) {
if (this is ErrorResponse) {
f.invoke(httpException.code(), httpException.message())
}
}
fun onConnectionFailed(f: (t: Throwable) -> Unit) {
if (this is ErrorRequest) {
f.invoke(t)
}
}
}
}
2-您应该为LiveData创建一个CallAdapterFactory
import retrofit2.*
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
class LiveDataCallAdapterFactory private constructor() : CallAdapter.Factory() {
companion object {
operator fun invoke() = LiveDataCallAdapterFactory()
}
override fun get(
returnType: Type, annotations: Array<out Annotation>, retrofit: Retrofit
): CallAdapter<*, *>? {
if (getRawType(returnType) != NetworkLiveData::class.java) {
return null
}
if (returnType !is ParameterizedType) {
throw IllegalStateException(
"must be parameterized"
)
}
val responseType = getParameterUpperBound(0, returnType)
return BodyCallAdapter<Any>(responseType)
}
private class BodyCallAdapter<T>(
private val responseType: Type
) : CallAdapter<T, NetworkLiveData<T>> {
override fun responseType() = responseType
override fun adapt(call: Call<T>): NetworkLiveData<T> {
val liveData = NetworkLiveData<T>()
call.enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>, t: Throwable) {
liveData.onFailedRequest(t)
liveData.onFinish()
}
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
liveData.onSuccessResponse(response.body())
} else {
liveData.onResponseHttpException(HttpException(response))
}
liveData.onFinish()
}
})
return liveData
}
}
}
您可以在this github repository中找到带有示例的完整代码。
关于java - 改造,实时数据适配器,使响应类包装程序通用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46384632/