【问题标题】:How to make custom implementation of Retrofit2.Call<T>如何自定义实现 Retrofit2.Call<T>
【发布时间】:2016-07-19 09:15:33
【问题描述】:

我正在使用 Retrofit2,我想重写它的 Call.enqueue 方法。

到目前为止我是这样做的:

自定义调用:

    public class CustomCall<T> implements Call<T> {

        private final Call<T> delegate;
        //..every method has delegate method invoked in it

API:

        @GET
        CustomCall<TKBaseResponse> testConnection(@Url String customUrl);

但我不断收到这些错误:

    Unable to create call adapter for CustomCall<....>

    Could not locate call adapter for CustomCall<....>

关于如何正确执行此操作的任何方法?提前致谢!

【问题讨论】:

标签: java android retrofit retrofit2 okhttp3


【解决方案1】:

首先创建一个ServiceManager类——

public final class ServiceManager {

    private static ServiceManager sServiceManager;

    /**
     * Gets the instance of the web services implementation.
     *
     * @return the singleton instance.
     */
    public static ServiceManager get() {
        if (sServiceManager == null) {
            sServiceManager = new ServiceManager();
        }
        return sServiceManager;
    }

    /**
     * Creates the services for a given HTTP Url, useful when testing
     * through multiple endpoints and unit testing
     *
     * @param clazz the service class.
     * @param <T>   type of the service.
     * @return the created services implementation.
     */
    public <T> T createService(Class<T> clazz) {
        return createService(clazz, HttpUrl.parse(ServiceApiEndpoints.SERVICE_ENDPOINT));
    }

    /**
     * Creates the services for a given HTTP Url, useful when testing
     * through multiple endpoints and unit testing
     *
     * @param clazz   the service class.
     * @param httpUrl the endpoint
     * @param <T>     type of the service.
     * @return the created services implementation.
     */
    public <T> T createService(Class<T> clazz, HttpUrl httpUrl) {
        Retrofit retrofit = getRetrofit(httpUrl);
        return retrofit.create(clazz);
    }

    public <T> T createService(Class<T> clazz, Retrofit retrofit) {
        return retrofit.create(clazz);
    }

    private Retrofit getRetrofit(HttpUrl httpUrl) {
        return new Retrofit.Builder()
                .baseUrl(httpUrl)
                .client(createClient())
                .addConverterFactory(getConverter())
                .build();
    }

    public Retrofit getPlainRetrofit(HttpUrl httpUrl) {
        return new Retrofit.Builder()
                .baseUrl(httpUrl)
                .client(new OkHttpClient.Builder().build())
                .addConverterFactory(getConverter())
                .build();
    }

    private Converter.Factory getConverter() {
        return GsonConverterFactory.create();
    }


    private OkHttpClient createClient() {
        return new OkHttpClient.Builder().addInterceptor(new RequestInterceptor()).build();
    }

}

ServiceApiEndpoints 是一个包含服务端点的类。

final class ServiceApiEndpoints {

    public static final String SERVICE_ENDPOINT = "your_app_url";
}

创建接口APIService

public interface APIService {
 String GET_INFO = "get_info";

    @GET(GET_INFO)
    Call<ResInfo[]> getInfo();
}

创建 ResInfo 模型。

public class ResInfo {
    private static final String FIELD_CONTENT = "content";

    public String getContent() {
        return mContent;
    }

    public void setContent(final String content) {
        mContent = content;
    }


    @SerializedName(FIELD_CONTENT)
    private String mContent;

    public ResInfo(){

    }
}

调用请求。

    private Call<ResInfo[]> mGetInfoAPICall;

    APIService apiService=ServiceManager.get().createService(APIService.class);
    mGetInfoAPICall = apiService.getInfo();
    mGetInfoAPICall.enqueue(new Callback<ResInfo[]>() {
    @Override
    public void onResponse(Call<ResInfo[]> call, Response<ResInfo[]> response) {

    }

    @Override
    public void onFailure(Call<ResInfo[]> call, Throwable t) {

    }
});

【讨论】:

    【解决方案2】:

    我在下面发布一个示例来帮助您进行改造。

    像这样创建您的资源 (MyResource.java)。

    Call<TKBaseResponse> testConnection(@@Url String customUrl);
    

    初始化改造

    private Resource getRetrofitResource(){
       //Initialize retrofit.
       final Retrofit = .....//your code to initialize retrofit
       return retrofit.create(MyResource.class);
    }
    

    要实现调用入队(异步改造调用),您需要将资源响应和响应处理程序(您的自定义实现)传递到入队方法中。我正在旁边发布我的 ResponseHandler 实现。

    public abstract class ResponseHandler<T> {
    
        private static final String TAG = ResponseHandler.class.getSimpleName();
    
        private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    
        private final Context context;
    
        public ResponseHandler() {
            this(null);
        }
    
        public ResponseHandler(final Context context) {
            this.context = context;
        }
    
    
        public abstract void onResponse(final T response);
    
        public void onError(final ErrorResponse errorResponse) {
            if (context == null) {
                return;
            }
            Log.e(TAG, "An error occurred while invoking service. Error Code: " + errorResponse.getErrorCode() + LINE_SEPARATOR + "Message: " + errorResponse.getMessage() + LINE_SEPARATOR);
            final AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
            alertBuilder.setCancelable(true);
            alertBuilder.setTitle(R.string.title_server_error_dialog);
            alertBuilder.setMessage(R.string.network_error_message);
            alertBuilder.setPositiveButton(R.string.text_ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(final DialogInterface dialog, final int which) {
                    dialog.dismiss();
                }
            });
            alertBuilder.show();
        }
    
        public void onFailure(Throwable throwable) {
            if (context == null) {
                return;
            }
            Log.e(TAG, "An error occurred while invoking service", throwable);
            final AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
            alertBuilder.setCancelable(true);
            alertBuilder.setTitle(R.string.title_network_error_dialog);
            alertBuilder.setMessage(R.string.network_error_message);
            alertBuilder.setPositiveButton(R.string.text_ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(final DialogInterface dialog, final int which) {
                    dialog.dismiss();
                }
            });
            alertBuilder.show();
        }
    
    }
    

    创建方法句柄响应。

    protected <T> void handleResponse(Call<T> call, final ResponseHandler<T> responseHandler) {
            call.enqueue(new Callback<T>() {
                @Override
                public void onResponse(final Call<T> call, final Response<T> response) {
                   if (response.isSuccess()) {
                    if (responseHandler != null ) {
                        responseHandler.onResponse(response.body());
                    }
                } else {
                    final ErrorResponse errorResponse = parseError(response);
                    if (responseHandler != null) {
                        responseHandler.onError(errorResponse);
                    }
                }
                }
    
                @Override
                public void onFailure(final Call<T> call, final Throwable throwable) {
                   if (responseHandler != null) {
                    responseHandler.onFailure(throwable);
                }
                }
            });
        }
    

    如果您对此有任何疑问,请告诉我。

    现在像下面这样调用你的资源。

    final MyResource resource = getRetrofitResource();
    final Call<TKBaseResponse> response = resource .testConnection("ANY_URL_OF_YOUR_CHOICE");
    handleResponse(response, new ResponseHandler<TKBaseResponse>(){
    
     public void onResponse(final TKBaseResponse response){
          //Do whatever you want to do here..
     }
        });
    

    【讨论】:

    • Resource来自哪个库?
    • MyResource 只是一个简单的 java 接口。您可以按照以下链接进行更深入的了解。 vogella.com/tutorials/Retrofit/article.html 我会抽出一些时间为你准备一个 git 项目来演示一个非常基本的用法和正确的代码结构。谢谢
    • 这并没有回答我关于如何覆盖 Call 的入队函数的问题
    • 我已经编辑了我的答案。如果您对 enqueue 函数实现有进一步的疑问,请告诉我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 2016-07-06
    • 1970-01-01
    相关资源
    最近更新 更多