retrofit原理

151 阅读6分钟

Retrofit的代码精简明了,设计巧妙。我们一起学习一下他的原理

使用

首先我们清楚,他是对Okhttp的一种封装,所以他依赖Okhttp,需要操作OkhttpClient

OkHttpClient client=new OkHttpClient.Builder().build();

Retrofit retrofit=new Retrofit.Builder().
   addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create())).  //设置gson转换器,将返回的json数据转为实体  
   addCallAdapterFactory(RxJavaCallAdapterFactory.create()).//设置CallAdapter工厂
   baseUrl(ApiServise.HOST).
   client(client) //设置客户端okhttp相关参数
   .build();

一般我们请求都是需要JSON转换,所以添加了JSON转换器,

为了使Retrofit支持Rxjava使用,添加工厂,后文我们讲解工厂类

addCallAdapterFactory(RxJavaCallAdapterFactory.create())

然后我们就可以写我们的接口请求逻辑了

返回数据实体类:
public class BaseReponse<T> {
    private int code;                   //响应码
    private String message;             //提示信息
    private T result;                  //返回的具体数据
    ...省略set/get方法
}

/**
 * 请求方法类
  */
public interface ApiServise {
    @FormUrlEncoded
    @POST("/getWangYiNews")
    Call<BaseReponse<List<NewsBean>>> getWangYiNews(@Field("page") String page, @Field("count") String count);
}

然后我们开测试一下,记得开网络权限

我们现在只是声明一个请求方法,他返回Call对象, 然后我们可以选择同步或异步调用,同Okhttp使用,注意一点,如果是同步调用,记得开线程。

retrofit.create(ApiServise.class).getWangYiNews("1", "5").enqueue(new  Callback<BaseReponse<List<NewsBean>>>() {
    @Override
    public void onResponse(Call<BaseReponse<List<NewsBean>>> call, Response<BaseReponse<List<NewsBean>>> response) {
    }

    @Override
    public void onFailure(Call<BaseReponse<List<NewsBean>>> call, Throwable t) {

    }
});

这样就完成了一个简单的请求

然后我们看怎么使用RxJava,我们在前文已经加入了Rxjava支持,所以使用起来非常简单

首先定义一个观察者类,只是为了统一以后的请求处理
public abstract class BaseObserver<T> implements Observer<BaseReponse<T>> {
    private Context mContext;

    public BaseObserver(Context mContext) {
        this.mContext = mContext;
    }

    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
        if (e instanceof ConnectException ||
                e instanceof TimeoutException ||
                e instanceof NetworkErrorException ||
                e instanceof UnknownHostException) {
            try {
                onFailure(e, false);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        } else {
            try {
                onFailure(e, true);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }

    @Override
    public void onNext(BaseReponse<T> tBaseReponse) {
        if (HttpUtils.isRequestSuccess(tBaseReponse.getCode())) {
            onSuccess(tBaseReponse);
        } else {
            onCodeError(tBaseReponse);
        }
    }

    //请求成功且返回码为200的回调方法,这里抽象方法申明
    public abstract void onSuccess(BaseReponse<T> tBaseReponse);

    //请求成功但返回的code码不是200的回调方法,这里抽象方法申明
    public abstract void onCodeError(BaseReponse tBaseReponse);

    //请求失败回调方法,这里抽象方法申明
    public abstract void onFailure(Throwable e, boolean netWork) throws Exception;
}

然后在ApiService中增加RxJava的接口

public interface ApiServise {
   ...省略第一个接口

    @FormUrlEncoded         //post请求必须要申明该注解
    @POST("/getWangYiNews")   //方法名
    Observable<BaseReponse<List<NewsBean>>> getWangYiNews2(@Field("page") String page,  @Field("count") String count);//请求参数
}

这样就可以了,然后我们写个测试

retrofit.create(ApiServise.class).getWangYiNews2("1", "5").
	subscribeOn(Schedulers.io()).
	observeOn(AndroidSchedulers.mainThread()).
	subscribe(new BaseObserver<List<NewsBean>>(context) {
    	@Override
   		public void onSuccess(BaseReponse<List<NewsBean>> t) {
    	}

    	@Override
    	public void onCodeError(BaseReponse baseReponse) {
    	}

    	@Override
    	public void onFailure(Throwable e, boolean netWork) throws Exception {
    	}
});

运行成功,我们可以看到跟RxJava的用法一样,拿到Observer之后就可以注册观察者,从而处理后续事情

原理分析

首先,Retrofit为了统一管理,用了动态代理

retrofit.create(ApiServise.class)

public <T> T create(final Class<T> service) {
  return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
      new InvocationHandler() {
        private final Platform platform = Platform.get();
        @Override public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          //加载类的方法,这个里面会根据返回数据类型查找合适的工厂,创建CallAdapter
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          //封装一个OkHttpCall对象
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          //让callAdapter去执行
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

我们看一下loadServiceMethod方法

ServiceMethod<?, ?> loadServiceMethod(Method method) {
  ServiceMethod<?, ?> result = serviceMethodCache.get(method);//做缓存,一个方法一份
  if (result != null) return result;//优先取缓存对象
  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
      result = new ServiceMethod.Builder<>(this, method).build();
      serviceMethodCache.put(method, result);//记入缓存
    }
  }
  return result;
}

然后跟踪ServiceMethod.Builder类

public ServiceMethod build() {
  callAdapter = createCallAdapter();
  //获取数据转换器
  responseConverter = createResponseConverter();
  //处理注解参数
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }

  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    //查找对应的注解处理器,一种注解只能对应一种处理器
    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
  }
  return new ServiceMethod<>(this);
}

private CallAdapter<T, R> createCallAdapter() {
      ...
      Type returnType = method.getGenericReturnType();
      Annotation[] annotations = method.getAnnotations();
      try {
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) {
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
}

继续追踪retrofit.callAdapter

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}
  
public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
  int start = adapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = adapterFactories.size(); i < count; i++) {
    //让工厂创建
    CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }

  throw new IllegalArgumentException(builder.toString());
}

然后我们看adapterFactories的操作,是在Retrofit的Builder中处理的,有一个系统默认的,用户可以通过addCallAdapterFactory方法添加自定义工厂,这样流程就比较清楚了

总结:

我们在ApiServise接口中声明的方法返回类型取决于CallAdapterFactory的支持,默认的工厂只支持返回Call类型,也就是我们的第一种写法,我们添加RxJavaCallAdapterFactory,就增加支持返回Observable类型。

由此我们得出结论,如果你想增加其他自定义返回类型,就需要自己实现CallAdapterFactory,并调用addCallAdapterFactory添加工厂列表,这样就可以了

自定义返回类型

按照我们设想的来做个例子

public interface HttpCallback<T> {
    void success(Response<T> response, HttpCall<T> httpCall);
    void clientError(Response<T> response, HttpCall<T> httpCall);
    void networkError(Throwable iOException, HttpCall<T> httpCall);
}
定义返回类型,这个跟okhttp的Call接口类似,只是enqueue方法的参数不同
public interface HttpCall<T> extends Cloneable {
    void cancel();
    HttpCall<T> clone();
    Response<T> execute() throws IOException;
    boolean isCanceled();
    boolean isExecuted();
    Request request();
    void enqueue(HttpCallback<T> callback);
}

然后我们在ApiService类增加一个方法

/**
 * post请求方式
 */
@FormUrlEncoded         //post请求必须要申明该注解
@POST("/getWangYiNews")   //方法名
HttpCall<BaseReponse<List<NewsBean>>> getWangYiNews(@Field("page") String page, @Field("count") String count);//请求参数

现在结构造好了,不能运行,因为默认callAdapter不识别

public class HttpCallAdapterFactory<R> extends CallAdapter.Factory {

    /* access modifiers changed from: private */
    public MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
    private HttpCallAdapterFactory() {
    }

    public static HttpCallAdapterFactory create() {//创建对象
        return new HttpCallAdapterFactory();
    }

    public CallAdapter<?, ?> get(Type type, Annotation[] annotationArr, Retrofit retrofit) {
        if (Types.getRawType(type) != HttpCall.class) {
            return null;
        }
        if (type instanceof ParameterizedType) {
            final Type parameterUpperBound = getParameterUpperBound(0, (ParameterizedType) type);
            //我们这里只返回了一种,你也可以根据type区分,来创建不同的CallAdapter
            return new CallAdapter<R, HttpCall<?>>() {
                public Type responseType() {
                    return parameterUpperBound;
                }

                @Override
                public HttpCall<?> adapt(Call<R> call) {
                    HttpCallAdapter httpCallAdapter = new HttpCallAdapter(call, HttpCallAdapterFactory.this.mMainThreadExecutor);
                    return httpCallAdapter;
                }
            };
        }
        throw new IllegalStateException("HttpCall must have generic type (e.g., HttpCall<ResponseBody>)");
    }

    class MainThreadExecutor implements Executor {
        private Handler mainHandler = new Handler(Looper.getMainLooper());

        MainThreadExecutor() {
        }

        public void execute(Runnable runnable) {
            this.mainHandler.post((Runnable) checkNotNull(runnable, "command == null"));
        }
    }
}

HttpCallAdapter的代码只是利用Okhttp的Call对象做一些操作,相当于一个静态代理

public class HttpCallAdapter<T> implements HttpCall<T> {
    private Call<T> mDelegate;
    public HttpCallAdapterFactory.MainThreadExecutor mMainThreadExecutor;

    public HttpCallAdapter(Call<T> call, HttpCallAdapterFactory.MainThreadExecutor mainThreadExecutor) {
        this.mDelegate = call;
        this.mMainThreadExecutor = mainThreadExecutor;
    }

    public Response<T> execute() throws IOException {
        return this.mDelegate.execute();
    }

    public void enqueue(final HttpCallback<T> httpCallback) {
        checkNotNull(httpCallback, "callback == null");
        this.mDelegate.enqueue(new Callback<T>() {
            public void onResponse(Call<T> call, final Response<T> response) {
                HttpCallAdapter.this.mMainThreadExecutor.execute(new Runnable() {
                    public void run() {
                        if (httpCallback == null) {
                            return;
                        }
                        int code = response.code();
                        if (HttpUtils.isRequestSuccess(code)) {
                            T body = response.body();
                            if (!response.isSuccessful()) {
                                return;
                            }
                            httpCallback.success(response, HttpCallAdapter.this);
                        } else{
                            httpCallback.clientError(response, HttpCallAdapter.this);
                        }
                    }
                });
            }

            public void onFailure(Call<T> call, final Throwable th) {
                HttpCallAdapter.this.mMainThreadExecutor.execute(new Runnable() {
                    public void run() {
                            httpCallback.networkError(th, HttpCallAdapter.this);
                    }
                });
            }
        });
    }

    public void cancel() {
        this.mDelegate.cancel();
    }

    public boolean isExecuted() {
        return this.mDelegate.isExecuted();
    }

    public boolean isCanceled() {
        return this.mDelegate.isCanceled();
    }

    public HttpCall<T> clone() {
        return new HttpCallAdapter(this.mDelegate.clone(), this.mMainThreadExecutor);
    }

    public Request request() {
        return this.mDelegate.request();
    }
}

然后我们把工厂类加入addCallAdapterFactory(HttpCallAdapterFactory.create())

好了,可以测试了,如果你的代码没有问题,应该能拿到结果了

具体代码可以在github查看:github.com/zytc2009/Ap…

更多学习和面试资料: github.com/zytc2009/Bi…

你要默默努力,然后悄悄拔尖。