I use an adapter to connect LiveData for modification, adapted from a Google sample
public interface ApiService {
@GET("?schema=1.2&form=cjson&byCategories=liveChannels&range=1-500&count=true")
LiveData<ApiResponse<Page<Media>>> getChannels();
}
I need to use different endpoints, so I want to make a generic ApiResponse. ApiResponse will be an interface or abstract and has different options from it for all of these endpoints; I do not want to write different LiveData extensions for each class that extends ApiResponse.
I want to do something like:
RetrofitLiveData<R, E extends ApiResponse<R>> extends LiveData<E<R>>
(I know the previous code does not compile, this is just an example of what I want)
and then in the modified interface I can:
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) {
}
public boolean isSuccessful() {
return code >= 200 && code < 300;
}
}
source
share