我使用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/

10-12 06:01