Retrofit2源碼解析(一)

一、適用人羣。會使用Retrofit,想更好更全面的瞭解Retrofit的童鞋。

二、解析
1、獲取Retrofit實例

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
    this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

成員變量解釋
1)callFactory 處理網絡請求的工廠類,依賴於okhttp3.Factory
2)baseUrl 網絡請求的基礎地址
3)converterFactories 實例類轉化工廠
4)adapterFactories CallAdapter生成工廠
5)callbackExecutor 回調的執行者,一個executor
6)validateEagerly 是否提前驗證methods是實現自接口

這裏着重說下converterFactories 和adapterFactories 的區別和作用

在Rxjava中,網絡請求的接口一般是這種形式

    public interface HttpLogin {
        @POST("account/login")
        XXX<YYY> login(@Body ZZZ body);
    }

converterFactories 是負責文字和實體類互相轉化,需要把http返回的body轉成yyy實體類,以及把ZZZ實體轉成字符串。
adapterFactories 是負責生成XXX實體類的適配器。在DefaultCallAdapterFactory.java文件中可以看出陸默認的僅支持XXX爲retrofit2.Call類型

看下默認賦值

public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

可以看出:
1) 必須設置baseUrl
2)默認使用okhttp3.OkHttpClient使用網絡請求工廠
3)callbackExecutor回調執行器用的是MainThreadExecutor,簡單的說就是在主線程回調

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

4)adapterFactories默認添加了retrofit2.DefaultCallAdapterFactory

DefaultCallAdapterFactory.class
 */
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
  //可以看出支持的返回類型僅爲retrofit2.Call,其他類型就不支持了
    if (getRawType(returnType) != Call.class) {
      return null;
    }

    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return call;
      }
    };
  }
}

5)converterFactories默認是個retrofit2.BuiltInConverters

retrofit2.BuiltInConverters代碼太多,就只貼出關鍵的
//可以看出只支持入參爲ResponseBody類型
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    if (type == ResponseBody.class) {
      if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
        return StreamingResponseBodyConverter.INSTANCE;
      }
      return BufferingResponseBodyConverter.INSTANCE;
    }
    if (type == Void.class) {
      return VoidResponseBodyConverter.INSTANCE;
    }
    return null;
  }

6)validateEagerly默認flase;

2、根據上面的要求創建一個請求接口

    public interface HttpLogin {
        @POST("account/login")
        retrofit2.Call<ResponseBody> login(@Body RequestBody body);
    }

1) retrofit2.Call login = retrofit.create(HttpLogin.class)
.login(RequestBody.create(MediaType.parse(“Application/json”), “{\”account\”:112333}”));
這裏看下Retrofit.create(final Class service) 函數

   public <T> T create(final Class<T> service) {
   //驗證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();

          @Override public Object invoke(Object proxy, Method method, Object... args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            //如果該方法在的類.class是Object.class
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }

            //如果是平臺的默認方法,在Android Platform恆爲false。
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }

            //將方法存緩存,然後取。。。就這樣
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

這裏出現了ServiceMethod,發現對它不瞭解的話就無法進行下去了。我們來看看
ServiceMethod類

public ServiceMethod.Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      //方法的註解集
      this.methodAnnotations = method.getAnnotations();
      //方法的參數類型集
      this.parameterTypes = method.getGenericParameterTypes();
      //方法的參數註解集(@path.etc)
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
//這裏只展現了一些核心代碼
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);
      }

        //解析接口的入參與入參註解
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }
      }

      return new ServiceMethod<>(this);
    }
ServiceMethod(Builder<T> builder) {
    //返回的類型的工廠類
    this.callFactory = builder.retrofit.callFactory();
    //請求的適配器
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    //返回類型的轉成實體類的轉化器
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    //請求的實際路徑。
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }

這時候得到了retrofit2.Call login對象,這個call很像Okhttp裏的Call;

這時候調用

   login.enqueue(new retrofit2.Callback<ResponseBody>() {
            @Override
            public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
                System.out.println("onResponse ");
                try {
                    System.out.println(response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) {
                System.out.println("onFailure " + t.getMessage());
            }
        });
        實際上調用了retrofit2.OkHttpCall<T>. enqueue(final Callback<T> callback)方法

 @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

//這裏是調用了okhttp.call的方法
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }
執行完。控件臺打印出
onResponse 
{"code":999999,"des":"參數錯誤[密碼不能爲空]"}

Process finished with exit code 0


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章