Retrofit源码分析

作者: 王小贱_ww | 来源:发表于2018-03-07 21:52 被阅读47次

    一.分析源码的基本姿势

    阅读源码.png
    抽茧剥丝看本质
    网络请求流程.png
    二.Retrofit是什么,有哪些API,有什么好处(what)
    1.先看Retrofit的文档https://square.github.io/retrofit/
    A type-safe HTTP client for Android and Java 这里看这个 type-safe,Retrofit通过泛型来约束我们想要的对象,自己不用去解析数据
    例子:
    public class MainActivity extends AppCompatActivity {
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textView = findViewById(R.id.text_content);
    
        }
    
        public void getHtttp(View view) {
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://gank.io/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            GitHubService gitHubService = retrofit.create(GitHubService.class);
            Call<BaseModel<ArrayList<Benefit>>> call = gitHubService.defautBenefits(20, 1);
            call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
                @Override
                public void onResponse(Call<BaseModel<ArrayList<Benefit>>> call, Response<BaseModel<ArrayList<Benefit>>> response) {
                    textView.setText(response.body().results.get(0).getDesc());
                }
    
                @Override
                public void onFailure(Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
    
                }
            });
    
        }
    }
    
    public interface GitHubService {
    
        @GET("api/data/福利/{pageCount}/{pageIndex}")
        Call<BaseModel<ArrayList<Benefit>>> defautBenefits(
                @Path("pageCount") int pageCount,
    
                @Path("pageIndex") int pageIndex
        );
    }
    
    public class BaseModel<T> {
    
        public boolean error;
        public T results;
    }
    
    
    public class Benefit {
    
    
        /**
         * _id : 5a8e0c41421aa9133298a259
         * createdAt : 2018-02-22T08:18:09.547Z
         * desc : 2-22
         * publishedAt : 2018-02-22T08:24:35.209Z
         * source : chrome
         * type : 福利
         * url : https://ws1.sinaimg.cn/large/610dc034ly1foowtrkpvkj20sg0izdkx.jpg
         * used : true
         * who : 代码家
         */
    
        private String _id;
        private String createdAt;
        private String desc;
        private String publishedAt;
        private String source;
        private String type;
        private String url;
        private boolean used;
        private String who;
    
        public String get_id() {
            return _id;
        }
    
        public void set_id(String _id) {
            this._id = _id;
        }
    
        public String getCreatedAt() {
            return createdAt;
        }
    
        public void setCreatedAt(String createdAt) {
            this.createdAt = createdAt;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        public String getPublishedAt() {
            return publishedAt;
        }
    
        public void setPublishedAt(String publishedAt) {
            this.publishedAt = publishedAt;
        }
    
        public String getSource() {
            return source;
        }
    
        public void setSource(String source) {
            this.source = source;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public boolean isUsed() {
            return used;
        }
    
        public void setUsed(boolean used) {
            this.used = used;
        }
    
        public String getWho() {
            return who;
        }
    
        public void setWho(String who) {
            this.who = who;
        }
    }
    

    三.debug拎出主线逻辑(how)
    debug!debug!debug!

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://gank.io/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
    

    retrofit 通过Builder模式来创建,先看看build()方法

    public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
    
          1.okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    
          2.Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
          // Make a defensive copy of the adapters and add the default Call adapter.
          3.List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // Make a defensive copy of the converters.
         4. List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }
    

      1.这里先判断callFactory 是否为空,如果为空,则new一个OkHttpClient,那为什么callFactory 只判断是否为空,没有判断callFactory的值呢?这里的工厂模式已经没有意义了,显而易见,Retrofit现在只支持OkHttpClient,不支持HttpClient和HttpConnection
      2.如果没有给我传入Executor ,这里new一个Executor

     static class Android extends Platform {
        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    
        @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
          if (callbackExecutor == null) throw new AssertionError();
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
    
        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
      }
    

    在MainThreadExecutor 中,我们声明了一个Handler,创建时我们传入了Looper.getMainLooper(),这里Handler在主线程中运行,execute()方法也在主线程中执行。
      3.把封装的Call转换成我们想要的Call对象(适配器模式)
      4.converterFactories断点调试可以看出是GsonConvertFactory
    最后构建成一个Retrofit。
    再看看retrofit.create(),创建一个实现类,看看怎么弄的

    public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
    //动态代理模式
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              private final Platform platform = Platform.get();
    //当调用api方法时,就会触发invoke
              @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
    //通过对注解的处理转换成我们想要的参数
    //dapts an invocation of an interface method into an HTTP call. 
    //例如:pageCount=20  pageIndex=1  
                ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
    //转换成OkHttpCall
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    //利用adapt方法,转换成我们想要的call
    //例如: Call<BaseModel<ArrayList<Benefit>>>  我们返回call
    //在rxJava中返回Observebal
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    

    最后返回的call调用enqueue方法

    @Override public void enqueue(final Callback<T> callback) {
          checkNotNull(callback, "callback == null");
    //代理delegate其实就是call
          delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
    //最后切回到主线程中执行了
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  if (delegate.isCanceled()) {
                    // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                  } else {
    //请求成功后进行回调
                    callback.onResponse(ExecutorCallbackCall.this, response);
                  }
                }
              });
            }
    
            @Override public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);
                }
              });
            }
          });
        }
    

    总结一下:
    Retrofit build
    Retrofit create proxy for API interface
    API method intercepted by proxy
    parse params with ServiceMethod
    build HttpCall with params
    CallAdapter adapts Call to T
    enqueue() waiting for callback
    四.直接看源码,画流程图

     ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
    

    在动态代理中,loadServiceMethod()会不会频繁的解析注解呢?

    ServiceMethod<?, ?> loadServiceMethod(Method method) {
    //看到serviceMethodCache就可以断定,有缓存
    //解析过的不会再解析了
        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;
      }
    
      OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    

    我们解析取来的注解参数,最后怎么能弄成我们想要的Okhttp的格式呢?serviceMethod传入了OkHttpCall类中
    看看OkHttpCall这个类,实现Call这个接口,接口Call中有同步请求、异步请求、取消、判断是否取消状态。OkHttpCall里面,对参数进行了包装(Request、RequestBody、OkHttp...),变成想要的OkHttpCall了。
    这行代码有点绕(= =)

    return serviceMethod.callAdapter.adapt(okHttpCall);
    

    先see see serviceMethod.callAdapter.怎么来的

    public ServiceMethod build() {
          callAdapter = createCallAdapter();
          responseType = callAdapter.responseType();
          if (responseType == Response.class || responseType == okhttp3.Response.class) {
            throw methodError("'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
          }
          responseConverter = createResponseConverter();
    
          for (Annotation annotation : methodAnnotations) {
    //进行解析注解
            parseMethodAnnotation(annotation);
          }
    .......
    省略代码了
    .......
    
    private CallAdapter<T, R> createCallAdapter() {
          Type returnType = method.getGenericReturnType();
          if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
          }
          if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
          }
          Annotation[] annotations = method.getAnnotations();
          try {
            //跳进这个方法
            return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
          } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(e, "Unable to create call adapter for %s", returnType);
          }
        }
    
    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
          Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
    
        int start = adapterFactories.indexOf(skipPast) + 1;
    //对于CallAdapter我们在Retrofit  build的时候把它初始化
    //在这里取出相应的adapter,如果我们不添加,默认的是ExecutorCallAdapterFactory
    //如果想配合RxJava使用(又是一种类型)
    //addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    //还要Java8、、、
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
          if (adapter != null) {
            return adapter;
          }
        }
    
        StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
            .append(returnType)
            .append(".\n");
        if (skipPast != null) {
          builder.append("  Skipped:");
          for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
          }
          builder.append('\n');
        }
        builder.append("  Tried:");
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
        }
        throw new IllegalArgumentException(builder.toString());
      }
    

    然后再调用adapt()方法,看一下ExecutorCallAdapterFactory中的方法

    @Override
    // Android中默认返回的是Call,在RxJava中返回Observable
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
    
          @Override public Call<Object> adapt(Call<Object> call) {
    //这里传递进来的是OkHttpCall
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    

    serviceMethod.callAdapter.adapt(okHttpCall)返回ExecutorCallbackCall,Retrofit的create也返回了ExecutorCallbackCall,这样Call<BaseModel<ArrayList<Benefit>>> call开始调用enqueue()方法了

    @Override public void enqueue(final Callback<T> callback) {
          checkNotNull(callback, "callback == null");
      //其实就是okhttpcall调用的enqueue方法
          delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  if (delegate.isCanceled()) {
                    // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                  } else {
                    callback.onResponse(ExecutorCallbackCall.this, response);
                  }
                }
              });
            }
    
            @Override public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);
                }
              });
            }
          });
        }
    

    进入OkHttpCall里面的方法,和Retrofit无关了
    在RealCall里面的代码

     @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
    //看这里    enqueue方法时异步方法!!!
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    

    最后,callback回调到最上层,我们还要找一下如何通过conventer来转换的?
    先看response
    OkHttpCall的类中的enqueue()方法

     response = parseResponse(rawResponse);
    
    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
    
        // Remove the body's source (the only stateful object) so we can pass the response along.
        rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();
    
        int code = rawResponse.code();
        if (code < 200 || code >= 300) {
          try {
            // Buffer the entire body to avoid future I/O.
            ResponseBody bufferedBody = Utils.buffer(rawBody);
            return Response.error(bufferedBody, rawResponse);
          } finally {
            rawBody.close();
          }
        }
    
        if (code == 204 || code == 205) {
          rawBody.close();
          return Response.success(null, rawResponse);
        }
    
        ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
        try {
          T body = serviceMethod.toResponse(catchingBody);
          return Response.success(body, rawResponse);
        } catch (RuntimeException e) {
          // If the underlying source threw an exception, propagate that rather than indicating it was
          // a runtime exception.
          catchingBody.throwIfCaught();
          throw e;
        }
      }
    
      R toResponse(ResponseBody body) throws IOException {
        return responseConverter.convert(body);
      }
    

    具体是GsonRequestBodyConverter来实现的,转换成我们需要的T

      @Override public T convert(ResponseBody value) throws IOException {
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        try {
          return adapter.read(jsonReader);
        } finally {
          value.close();
        }
      }
      }
    

    再来看看request(把注解转换成参数)OkhttpCall类

      private okhttp3.Call createRawCall() throws IOException {
    //跳进去
        Request request = serviceMethod.toRequest(args);
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    

    ServiceMethod类

    Request toRequest(@Nullable Object... args) throws IOException {
    //我们看看RequestBuilder中的RequestBody
        RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
            contentType, hasBody, isFormEncoded, isMultipart);
    
        @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
        ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    
        int argumentCount = args != null ? args.length : 0;
        if (argumentCount != handlers.length) {
          throw new IllegalArgumentException("Argument count (" + argumentCount
              + ") doesn't match expected count (" + handlers.length + ")");
        }
    
        for (int p = 0; p < argumentCount; p++) {
          handlers[p].apply(requestBuilder, args[p]);
        }
    
        return requestBuilder.build();
      }
    

    RequestBuilder类

      void setBody(RequestBody body) {
        this.body = body;
      }
    

    我们看看这个方法在哪里被调用了
    ParameterHandler类

    @Override void apply(RequestBuilder builder, @Nullable T value) {
          if (value == null) {
            throw new IllegalArgumentException("Body parameter value must not be null.");
          }
          RequestBody body;
          try {
    //  !!!!!!!!在这里  GsonResponseBodyConverter实现了这个方法
            body = converter.convert(value);
          } catch (IOException e) {
            throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
          }
          builder.setBody(body);
        }
    
    流程图.jpg

    相关文章

      网友评论

        本文标题:Retrofit源码分析

        本文链接:https://www.haomeiwen.com/subject/ppjlfftx.html