Retrofit從使用到原理

使用Retrofit

網(wǎng)上使用Retrofit的好文章很多,我也就不重復(fù)造輪子。給大家推薦一些文章:看了這些文章你如真的理解Retrofit,你會(huì)發(fā)現(xiàn)其實(shí)下面實(shí)現(xiàn)的功能,其實(shí)很多是對(duì)OkHttp的操作,因?yàn)镽etrofit底層請(qǐng)求使用的就是OkHttp,Retrofit的真正的作用就是你可以用注解接口的方式請(qǐng)求。當(dāng)然Retrofit也做了很多細(xì)節(jié)處理,做到了類型安全等。

解析Retrofit的核心結(jié)構(gòu)

一般使用Retrofit會(huì)分下面幾步
  • Retrofit會(huì)把http api請(qǐng)求用java接口的方式呈現(xiàn)。
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
  • Retrofit會(huì)通過動(dòng)態(tài)代理生成GitHubService。
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);
  • 通過生成的GitHubService,創(chuàng)建不同的call的http請(qǐng)求。通過enqueue方法,或者execute方法,讓其異步或者同步執(zhí)行。
Call<List<Repo>> repos = service.listRepos("octocat");

repos.enqueue(new Callback<List<Repo>>() {
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                
            }

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

            }
        });

核心原理分析

通過Retrofit.create()創(chuàng)建出Service interface的實(shí)例,從而使得Service中配置的方法變得可用,這是Retrofit代碼結(jié)構(gòu)的核心。跟進(jìn)retrofit.create()的方法,首先檢查service是不是接口并且繼承接口,讓后看看是否需要提前創(chuàng)建方法,放入serviceMethodCache中,默認(rèn)不需要。最后就是重點(diǎn)動(dòng)態(tài)代理,創(chuàng)建動(dòng)態(tài)對(duì)象。動(dòng)態(tài)代理的優(yōu)勢(shì)在于可以很方便的對(duì)代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個(gè)代理類中的方法。是因?yàn)樗斜淮韴?zhí)行的方法,都是通過在InvocationHandler中的invoke方法調(diào)用的,所以我們只要在invoke方法中統(tǒng)一處理,就可以對(duì)所有被代理的方法進(jìn)行相同的操作了。具體動(dòng)態(tài)代理相關(guān)內(nèi)容可以看這篇文章:java動(dòng)態(tài)代理實(shí)現(xiàn)與原理

  public <T> T create(final Class<T> service) {
    //檢查service,是不是接口,是否繼承接口。要求service是接口且不繼承其他接口
    Utils.validateServiceInterface(service);
   //默認(rèn)為false,判斷是否需要提前l(fā)oadServiceMethod(method);
    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, @Nullable Object[] args)
              throws Throwable {
            //如果方法來自object或者platform,那就正常調(diào)用
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //重點(diǎn)內(nèi)容
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

下面是三行代碼就是整個(gè)create方法的核心,創(chuàng)建一個(gè)實(shí)現(xiàn)service接口類的實(shí)例。

ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
第一行:ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);

ServiceMethod將一個(gè)接口方法適配成為一個(gè)HTTP請(qǐng)求,讀取網(wǎng)絡(luò)請(qǐng)求接口里的方法,并根據(jù)前面配置好的屬性配置serviceMethod對(duì)象。loadServiceMethod方法的作用就是將接口注解解析,并存到serviceMethodCache中。下面的代碼邏輯:如果serviceMethodCache中存在,就直接返回結(jié)果。然后同步以下內(nèi)容操作:再次從serviceMethodCache中嘗試獲取,如果還是沒有,就自己創(chuàng)建,然后將創(chuàng)建的好的對(duì)象放入serviceMechodCache中。

  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;
  }

如何創(chuàng)建ServiceMethod,就在ServiceMethod.Builder<>(this, method).build()中實(shí)現(xiàn),下面就是源碼,主要作用就是負(fù)責(zé)讀取interface中原方法的信息:返回值類型,請(qǐng)求方法注解,參數(shù)類型,參數(shù)注解。同時(shí)也創(chuàng)建callAdapter,responseConverter等后續(xù)請(qǐng)求和返回?cái)?shù)據(jù)轉(zhuǎn)換會(huì)用到的對(duì)象,同時(shí)調(diào)用parseMethodAnnotation,parseParameter方法將注解的方法和參數(shù)組裝好。然后返回ServiceMethod對(duì)象。

    public ServiceMethod build() {
     //創(chuàng)建CallAdapter,默認(rèn)創(chuàng)建ExecutorCallAdapterFactory
      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);
      }
      //請(qǐng)求方法的驗(yàn)證
      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

      //請(qǐng)求參數(shù)的驗(yàn)證
      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);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
第二行:OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall的創(chuàng)建:下面這行代碼主要負(fù)責(zé)將ServiceMethod封裝近一個(gè)retrofit2.call對(duì)象中。在使用enqueue()方法中,利用ServiceMethod中包含的信息創(chuàng)建一個(gè)okhttp3.Call對(duì)象,并調(diào)用okhttp3.Call對(duì)象來進(jìn)行網(wǎng)絡(luò)請(qǐng)求的發(fā)起,然后對(duì)結(jié)果進(jìn)行處理。也就是說retrofit2.Call包裝了一個(gè)okhttp3.Call,所有的工作都由okhttp3.Call來進(jìn)行處理。一句話就是變成okhttpcall,進(jìn)行真正的網(wǎng)絡(luò)請(qǐng)求。如果是不能再主線程中執(zhí)行的請(qǐng)求,例如下面的enqueue方法:
enqueue方式中明顯的看到用createRawCall方法創(chuàng)建出一個(gè)okhttp3.call的方法,然后讓真實(shí)去做請(qǐng)求的okhttp3.call去做enqueue方法。

  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "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) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

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

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

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

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

createRawCall做了什么?erviceMethod.toCall(args)將解析注解得到的請(qǐng)求方法,請(qǐng)求參數(shù)構(gòu)建成一個(gè)okhttp3.call。具體如何構(gòu)建,我也沒有仔細(xì)看過。

private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
第三行:serviceMethod.adapt(okHttpCall)

adapt()方法就是把okHttpCall對(duì)象進(jìn)行轉(zhuǎn)化,生成一個(gè)新的retrofit2.Call對(duì)象,這樣就變回去了,上一步將retrofit2.call對(duì)象變成OkHttpCall3.call去進(jìn)行網(wǎng)絡(luò)請(qǐng)求。其實(shí)這個(gè)方法也可以生成別的對(duì)象,如果Retrofit中添加addCallAdapterFactory(RxJava2CallAdapterFactory.create()),Rxjava的Obervable同樣也可以被創(chuàng)建。

  T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }

callAdapter是網(wǎng)絡(luò)請(qǐng)求適配器,將默認(rèn)的網(wǎng)絡(luò)請(qǐng)求執(zhí)行器(OkHttpCall)轉(zhuǎn)換成適合被不同平臺(tái)來調(diào)用的網(wǎng)絡(luò)請(qǐng)求執(zhí)行器形式,通過createCallAdapter()產(chǎn)生,我們一步一步的跟進(jìn),調(diào)用retrofit.callAdapter(returnType, annotations);

    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 {
        //noinspection unchecked
        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);
      }
    }

然后再調(diào)用nextCallAdapter(null, returnType, annotations)

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

在nextCallAdapter()方法中,調(diào)用CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this)來找到adapter,查找callAdapterFactory,在Retrofit中提供了四種CallAdapterFactory: ExecutorCallAdapterFactory(默認(rèn))、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory。
在Retrofit.build()的中會(huì)給callAdapterFactories添加CallAdapterFactorie,如果沒有添加RxJavaCallAdapter之類就按默認(rèn)提供的CallAdapterFactory。

      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
  CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

  boolean isDefaultMethod(Method method) {
    return false;
  }

  @Nullable Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
      @Nullable Object... args) throws Throwable {
    throw new UnsupportedOperationException();
  }

我們知道默認(rèn)的callAdapter來自ExecutorCallAdapterFactory,找到adapt()方法,從okhttp.call適配成retrofit.call。

 @Override
  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) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

進(jìn)入ExecutorCallbackCal中,delegate就是一個(gè)okhttp3.call,有我們的生成的okhttpCall傳入。印證了我們之前收到,無論轉(zhuǎn)化成Retrofit2.call還是RxJava的observable,最后正常的進(jìn)行網(wǎng)絡(luò)請(qǐng)求的還是okhttp3.call。

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      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);
            }
          });
        }
      });
    }
   ......
}

enqueue方法具有切換功能原因就在這里,new Handler(Looper.getMainLooper())

  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);
      }
    }
  }
}
總結(jié)

Retrofit的總體邏輯就是上面內(nèi)容,下面有一篇介紹的比較詳細(xì)
Android:手把手帶你 深入讀懂 Retrofit 2.0 源碼

三件套缺一不可:

OkHttp從使用到原理
Retrofit從使用到原理
RxJava從使用到原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄介紹 1.首先回顧Retrofit簡(jiǎn)單使用方法 2.Retrofit的創(chuàng)建流程源碼分析2.1 Retrofit...
    楊充211閱讀 1,178評(píng)論 0 16
  • 最近非常流行 Retrofit+RxJava+OkHttp 這一整套的網(wǎng)絡(luò)請(qǐng)求和異步操作的開源框架,從 Jake ...
    慌不要慌閱讀 2,022評(píng)論 1 7
  • 適配器模式上一篇文章我們已經(jīng)分析了Retrofit解析注解封裝進(jìn)ServiceMethod的流程,讀者在這里要記住...
    andcoder閱讀 775評(píng)論 0 2
  • 2016/07/21上海Read the fucking source code。 開始之前,先回想下一個(gè)網(wǎng)絡(luò)請(qǐng)求...
    ImmortalHalfWu閱讀 997評(píng)論 2 12
  • 生活不曾取悅于我 所以我創(chuàng)造了自己的生活 與其在意別人的背棄和不善 不如經(jīng)營自己的尊嚴(yán)和美好
    二白啊閱讀 146評(píng)論 0 0

友情鏈接更多精彩內(nèi)容