码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Retrofit原理 一篇文章就够了


    我们网络访问已经有了OkHttp,那为什么还需要一个Retrofit呢?

    我们先来看一下一个基本的OkHttp请求的步骤:

    1. String url = "http://wwww.baidu.com";
    2. OkHttpClient okHttpClient = new OkHttpClient();
    3. final Request request = new Request.Builder()
    4. .url(url)
    5. .get()//默认就是GET请求,可以不写
    6. .build();
    7. Call call = okHttpClient.newCall(request);
    8. call.enqueue(new Callback() {
    9. @Override
    10. public void onFailure(Call call, IOException e) {
    11. Log.d(TAG, "onFailure: ");
    12. }
    13. @Override
    14. public void onResponse(Call call, Response response) throws IOException {
    15. Log.d(TAG, "onResponse: " + response.body().string());
    16. }
    17. });

    这样的请求其实有几个问题:

    • response需要手动解析
    • 线程需要手动切换
    • 请求回调代码无法复用
    • 网络请求回调陷阱

    我们知道Retrofit是基于OkHttp的一层封装,Retrofit本身不负责网络请求,而是将请求交给OkHttp处理。我们知道,Retrofit的请求是写在一个个接口里面的,这样同样baseUrl的请求就可以写在一个接口里面,非常方便拓展和管理。而且直接将数据解析到javaBean,并且自动切换线程。这样就有效的解决了OkHttp的使用问题。

    上图是对Retrofit职责的一个很好的描述。

    我们来看一下Retrofit的基本使用:

    1. //step1
    2. Retrofit retrofit = new Retrofit.Builder()
    3. .baseUrl("https://www.wanandroid.com/")
    4. .addConverterFactory(GsonConverterFactory.create(new Gson()))
    5. .build();
    6. //step2
    7. ISharedListService sharedListService = retrofit.create(ISharedListService.class);
    8. //step3
    9. Call sharedListCall = sharedListService.getSharedList(2,1);
    10. //step4
    11. sharedListCall.enqueue(new Callback() {
    12. @Override
    13. public void onResponse(Call call, Response response{
    14. if (response.isSuccessful()) {
    15. System.out.println(response.body().toString());
    16. }
    17. }
    18. @Override
    19. public void onFailure(Call call, Throwable t) {
    20. t.printStackTrace();
    21. }
    22. });

    我们先来看build方法做了什么事情:

    1. public Retrofit build() {
    2. if (baseUrl == null) {
    3. throw new IllegalStateException("Base URL required.");
    4. }
    5. okhttp3.Call.Factory callFactory = this.callFactory;
    6. if (callFactory == null) {
    7. callFactory = new OkHttpClient();//1
    8. }
    9. Executor callbackExecutor = this.callbackExecutor;
    10. if (callbackExecutor == null) {
    11. callbackExecutor = platform.defaultCallbackExecutor();//2
    12. }
    13. // Make a defensive copy of the adapters and add the default Call adapter.
    14. List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    15. callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    16. // Make a defensive copy of the converters.
    17. List converterFactories =
    18. new ArrayList<>(
    19. 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    20. // Add the built-in converter factory first. This prevents overriding its behavior but also
    21. // ensures correct behavior when using converters that consume all types.
    22. converterFactories.add(new BuiltInConverters());
    23. converterFactories.addAll(this.converterFactories);
    24. converterFactories.addAll(platform.defaultConverterFactories());
    25. return new Retrofit(
    26. callFactory,
    27. baseUrl,
    28. unmodifiableList(converterFactories),
    29. unmodifiableList(callAdapterFactories),
    30. callbackExecutor,
    31. validateEagerly);
    32. }
    33. }

    注释1处可见创建了一个OkHttpClient。这里也用到了建造者设计模式。那我们要思考一下,何时该使用建造者模式呢?好多人看了大量的设计模式书籍,可是代码风格依然一眼难尽!

    1. public static final class Builder {
    2. private final Platform platform;
    3. private @Nullable okhttp3.Call.Factory callFactory;
    4. private @Nullable HttpUrl baseUrl;
    5. private final List converterFactories = new ArrayList<>();
    6. private final List callAdapterFactories = new ArrayList<>();
    7. private @Nullable Executor callbackExecutor;
    8. private boolean validateEagerly;
    9. Builder(Platform platform) {
    10. this.platform = platform;
    11. }
    12. public Builder() {
    13. this(Platform.get());
    14. }
    15. Builder(Retrofit retrofit) {
    16. platform = Platform.get();
    17. callFactory = retrofit.callFactory;
    18. baseUrl = retrofit.baseUrl;
    19. // Do not add the default BuiltIntConverters and platform-aware converters added by build().
    20. for (int i = 1,
    21. size = retrofit.converterFactories.size() - platform.defaultConverterFactoriesSize();
    22. i < size;
    23. i++) {
    24. converterFactories.add(retrofit.converterFactories.get(i));
    25. }
    26. // Do not add the default, platform-aware call adapters added by build().
    27. for (int i = 0,
    28. size =
    29. retrofit.callAdapterFactories.size() - platform.defaultCallAdapterFactoriesSize();
    30. i < size;
    31. i++) {
    32. callAdapterFactories.add(retrofit.callAdapterFactories.get(i));
    33. }
    34. callbackExecutor = retrofit.callbackExecutor;
    35. validateEagerly = retrofit.validateEagerly;
    36. }
    37. /**
    38. * The HTTP client used for requests.
    39. *
    40. *

      This is a convenience method for calling {@link #callFactory}.

    41. */
    42. public Builder client(OkHttpClient client) {
    43. return callFactory(Objects.requireNonNull(client, "client == null"));
    44. }
    45. /**
    46. * Specify a custom call factory for creating {@link Call} instances.
    47. *
    48. *

      Note: Calling {@link #client} automatically sets this value.

    49. */
    50. public Builder callFactory(okhttp3.Call.Factory factory) {
    51. this.callFactory = Objects.requireNonNull(factory, "factory == null");
    52. return this;
    53. }
    54. /**
    55. * Set the API base URL.
    56. *
    57. * @see #baseUrl(HttpUrl)
    58. */
    59. public Builder baseUrl(URL baseUrl) {
    60. Objects.requireNonNull(baseUrl, "baseUrl == null");
    61. return baseUrl(HttpUrl.get(baseUrl.toString()));
    62. }
    63. /**
    64. * Set the API base URL.
    65. *
    66. * @see #baseUrl(HttpUrl)
    67. */
    68. public Builder baseUrl(String baseUrl) {
    69. Objects.requireNonNull(baseUrl, "baseUrl == null");
    70. return baseUrl(HttpUrl.get(baseUrl));
    71. }
    72. /**
    73. * Set the API base URL.
    74. *
    75. *

      The specified endpoint values (such as with {@link GET @GET}) are resolved against this

    76. * value using {@link HttpUrl#resolve(String)}. The behavior of this matches that of an {@code
    77. * } link on a website resolving on the current URL.
    78. *
    79. *

      Base URLs should always end in {@code /}.

    80. *
    81. *

      A trailing {@code /} ensures that endpoints values which are relative paths will correctly

    82. * append themselves to a base which has path components.
    83. *
    84. *

      Correct:

    85. * Base URL: http://example.com/api/
    86. * Endpoint: foo/bar/
    87. * Result: http://example.com/api/foo/bar/
    88. *
    89. *

      Incorrect:

    90. * Base URL: http://example.com/api
    91. * Endpoint: foo/bar/
    92. * Result: http://example.com/foo/bar/
    93. *
    94. *

      This method enforces that {@code baseUrl} has a trailing {@code /}.

    95. *
    96. *

      Endpoint values which contain a leading {@code /} are absolute.

    97. *
    98. *

      Absolute values retain only the host from {@code baseUrl} and ignore any specified path

    99. * components.
    100. *
    101. *

      Base URL: http://example.com/api/

    102. * Endpoint: /foo/bar/
    103. * Result: http://example.com/foo/bar/
    104. *
    105. *

      Base URL: http://example.com/

    106. * Endpoint: /foo/bar/
    107. * Result: http://example.com/foo/bar/
    108. *
    109. *

      Endpoint values may be a full URL.

    110. *
    111. *

      Values which have a host replace the host of {@code baseUrl} and values also with a scheme

    112. * replace the scheme of {@code baseUrl}.
    113. *
    114. *

      Base URL: http://example.com/

    115. * Endpoint: https://github.com/square/retrofit/
    116. * Result: https://github.com/square/retrofit/
    117. *
    118. *

      Base URL: http://example.com

    119. * Endpoint: //github.com/square/retrofit/
    120. * Result: http://github.com/square/retrofit/ (note the scheme stays 'http')
    121. */
    122. public Builder baseUrl(HttpUrl baseUrl) {
    123. Objects.requireNonNull(baseUrl, "baseUrl == null");
    124. List pathSegments = baseUrl.pathSegments();
    125. if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    126. throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
    127. }
    128. this.baseUrl = baseUrl;
    129. return this;
    130. }
    131. /** Add converter factory for serialization and deserialization of objects. */
    132. public Builder addConverterFactory(Converter.Factory factory) {
    133. converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
    134. return this;
    135. }
    136. /**
    137. * Add a call adapter factory for supporting service method return types other than {@link
    138. * Call}.
    139. */
    140. public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
    141. callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
    142. return this;
    143. }
    144. /**
    145. * The executor on which {@link Callback} methods are invoked when returning {@link Call} from
    146. * your service method.
    147. *
    148. *

      Note: {@code executor} is not used for {@linkplain #addCallAdapterFactory custom method

    149. * return types}.
    150. */
    151. public Builder callbackExecutor(Executor executor) {
    152. this.callbackExecutor = Objects.requireNonNull(executor, "executor == null");
    153. return this;
    154. }
    155. /** Returns a modifiable list of call adapter factories. */
    156. public List callAdapterFactories() {
    157. return this.callAdapterFactories;
    158. }
    159. /** Returns a modifiable list of converter factories. */
    160. public List converterFactories() {
    161. return this.converterFactories;
    162. }
    163. /**
    164. * When calling {@link #create} on the resulting {@link Retrofit} instance, eagerly validate the
    165. * configuration of all methods in the supplied interface.
    166. */
    167. public Builder validateEagerly(boolean validateEagerly) {
    168. this.validateEagerly = validateEagerly;
    169. return this;
    170. }
    171. /**
    172. * Create the {@link Retrofit} instance using the configured values.
    173. *
    174. *

      Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link

    175. * OkHttpClient} will be created and used.
    176. */
    177. public Retrofit build() {
    178. if (baseUrl == null) {
    179. throw new IllegalStateException("Base URL required.");
    180. }
    181. okhttp3.Call.Factory callFactory = this.callFactory;
    182. if (callFactory == null) {
    183. callFactory = new OkHttpClient();
    184. }
    185. Executor callbackExecutor = this.callbackExecutor;
    186. if (callbackExecutor == null) {
    187. callbackExecutor = platform.defaultCallbackExecutor();
    188. }
    189. // Make a defensive copy of the adapters and add the default Call adapter.
    190. List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    191. callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    192. // Make a defensive copy of the converters.
    193. List converterFactories =
    194. new ArrayList<>(
    195. 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    196. // Add the built-in converter factory first. This prevents overriding its behavior but also
    197. // ensures correct behavior when using converters that consume all types.
    198. converterFactories.add(new BuiltInConverters());
    199. converterFactories.addAll(this.converterFactories);
    200. converterFactories.addAll(platform.defaultConverterFactories());
    201. return new Retrofit(
    202. callFactory,
    203. baseUrl,
    204. unmodifiableList(converterFactories),
    205. unmodifiableList(callAdapterFactories),
    206. callbackExecutor,
    207. validateEagerly);
    208. }
    209. }

    我们先来看一下Retrofit的静态内部类Builder,里面的baseUrl,addConverterFactory等方法返回的都是Builder类型,说明了在使用的时候可以做到可配置,另外一个大家都比较清楚,就是参数比较多的情况,一般认为在5个以上。

    我们分析完Retrofit的使用的第一步,接下来看第二步:

    ISharedListService sharedListService =  retrofit.create(ISharedListService.class);

    点进create看一下:

    1. public T create(final Class service) {
    2. validateServiceInterface(service);
    3. return (T)
    4. Proxy.newProxyInstance(
    5. service.getClassLoader(),
    6. new Class[] {service},
    7. new InvocationHandler() {
    8. private final Platform platform = Platform.get();
    9. private final Object[] emptyArgs = new Object[0];
    10. @Override
    11. public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
    12. throws Throwable {
    13. // If the method is a method from Object then defer to normal invocation.
    14. if (method.getDeclaringClass() == Object.class) {
    15. return method.invoke(this, args);
    16. }
    17. args = args != null ? args : emptyArgs;
    18. return platform.isDefaultMethod(method)
    19. ? platform.invokeDefaultMethod(method, service, proxy, args)
    20. : loadServiceMethod(method).invoke(args);
    21. }
    22. });
    23. }

    大家可能或多或少了解过一些关于代理设计模式,可是你真的熟悉或者说了解代理设计模式吗?

    代理模式分为静态代理和动态代理,如果大家不熟悉静态代理模式,可以看下我以前的一篇文章:

    设计模式 - 静态代理模式_AD钙奶-lalala的博客-CSDN博客生活中我们都有过去银行办理银行卡的体验,一般会有银行工作人员协助办理银行卡,那么这个工作人员就是一个代理,这种模式就是代理模式。我们用java代码简单实现一下这个场景首先将需要代理的事件写在一个接口里面:public interface IBank { //申请办卡 void applyCard();}银行卡实际办理人:public class Man...https://blog.csdn.net/qq_36428821/article/details/103491205这里就不展开了。

    下面重点讲一下动态代理,我们先来看newProxyInstance这个方法:

    1. public static Object newProxyInstance(ClassLoader loader,
    2. Class[] interfaces,
    3. InvocationHandler h)
    4. throws IllegalArgumentException
    5. {

    发现返回的是一个Object类型的对象,所以create方法本质上是返回了一个实现指定接口的对象。

    1. public static Object newProxyInstance(ClassLoader loader,
    2. Class[] interfaces,
    3. InvocationHandler h)
    4. throws IllegalArgumentException
    5. {
    6. Objects.requireNonNull(h);
    7. final Class[] intfs = interfaces.clone();
    8. Class cl = getProxyClass0(loader, intfs);
    9. try {
    10. final Constructor cons = cl.getConstructor(constructorParams);
    11. final InvocationHandler ih = h;
    12. if (!Modifier.isPublic(cl.getModifiers())) {
    13. cons.setAccessible(true);
    14. // END Android-removed: Excluded AccessController.doPrivileged call.
    15. }
    16. return cons.newInstance(new Object[]{h});//1
    17. } catch (IllegalAccessException|InstantiationException e) {
    18. throw new InternalError(e.toString(), e);
    19. } catch (InvocationTargetException e) {
    20. Throwable t = e.getCause();
    21. if (t instanceof RuntimeException) {
    22. throw (RuntimeException) t;
    23. } else {
    24. throw new InternalError(t.toString(), t);
    25. }
    26. } catch (NoSuchMethodException e) {
    27. throw new InternalError(e.toString(), e);
    28. }
    29. }

    注意注释1处,通过构造函数初始化了一个对象,并将h传了进去,这个h是啥呢?很明显:

    是实现InvocationHandler接口的一个对象。我们来写一个create生成的实现传入接口的对象的伪代码帮大家理解一下动态代理:

    我们前面看到cons.newInstance(new Object[]{h})传进来一个h,再看上图,调用了h的invoke方法,这样是不是有点顿悟的感觉。简而言之,动态代理的原理就是:Proxy.newProxyInstance生成一个实现某个接口的对象,并且传入一个实现InvocationHandler接口的对象,当该对象调用实现接口的方法时,实际上调用的实现InvocationHandler接口的对象的invoke方法,并且将接口方法和参数也传进来,后面在invoke里面反射调用。

    这样讲大家可能还不是很明白,说的简单点吧:Retrofit请求我们写成一个一个的接口,而这些接口最终通过Proxy.newProxyInstance最终会生成实现这个接口的对象,这是第一步;而生成这个对象的时候,在构造中传入了实现InvocationHandler接口的的对象,紧接着调用这个对象的invoke方法,并将方法信息以及方法参数传过去,实际上实现这个接口的的方法调用是在实现InvocationHandler接口的的对象中进行的,而实现我们所写接口的对象的方法只是调用了this.h.invoke。

    下面再讲一个Retrofit非常重要的一个点:线程切换。我们知道OkHttp的回调里面是没有切换线程的,这样我们使用的时候就会需要手动切换线程,不是那么的友好。

    我们先看Retrofit里面的一段代码:

    1. public Retrofit build() {
    2. ···
    3. Executor callbackExecutor = this.callbackExecutor;
    4. if (callbackExecutor == null) {
    5. callbackExecutor = platform.defaultCallbackExecutor();//1
    6. }
    7. ···
    8. }

    我们进注释1看看实现,我们是Android平台:

    1. static final class Android extends Platform {
    2. Android() {
    3. super(Build.VERSION.SDK_INT >= 24);
    4. }
    5. @Override
    6. public Executor defaultCallbackExecutor() {
    7. return new MainThreadExecutor();//1
    8. }
    9. @Nullable
    10. @Override
    11. Object invokeDefaultMethod(
    12. Method method, Class declaringClass, Object object, Object... args) throws Throwable {
    13. if (Build.VERSION.SDK_INT < 26) {
    14. throw new UnsupportedOperationException(
    15. "Calling default methods on API 24 and 25 is not supported");
    16. }
    17. return super.invokeDefaultMethod(method, declaringClass, object, args);
    18. }
    19. static final class MainThreadExecutor implements Executor {
    20. private final Handler handler = new Handler(Looper.getMainLooper());
    21. @Override
    22. public void execute(Runnable r) {
    23. handler.post(r);//2
    24. }
    25. }
    26. }

    原来本质上是用了Handler,记住一个很重要的结论:Android中线程切换最终都是Handler,进程间通信绝大部分都是Binder。

    我们既然知道了Retrofit是使用Handler来进行线程切换的,那么它是如何使用的呢?

    我们再来看下面的代码:

    1. return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
    2. new InvocationHandler() {
    3. private final Platform platform = Platform.get();
    4. @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
    5. throws Throwable {
    6. // If the method is a method from Object then defer to normal invocation.
    7. if (method.getDeclaringClass() == Object.class) {
    8. return method.invoke(this, args);
    9. }
    10. if (platform.isDefaultMethod(method)) {
    11. return platform.invokeDefaultMethod(method, service, proxy, args);
    12. }
    13. ServiceMethod serviceMethod =
    14. (ServiceMethod) loadServiceMethod(method);//1
    15. OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);//2
    16. return serviceMethod.callAdapter.adapt(okHttpCall);//3
    17. }
    18. });
    19. (注:这个代码是Retrofit2.3.0版本的,前面是2.9.0版本的,有些不一样,但是这个版本线程切换更好理解)

      先来看注释1:

      1. ServiceMethod loadServiceMethod(Method method) {
      2. ServiceMethod result = serviceMethodCache.get(method);
      3. if (result != null) return result;
      4. synchronized (serviceMethodCache) {
      5. result = serviceMethodCache.get(method);
      6. if (result == null) {
      7. result = new ServiceMethod.Builder<>(this, method).build();
      8. serviceMethodCache.put(method, result);
      9. }
      10. }
      11. return result;
      12. }

      我们只需要关注一点,这里面传入了this,而这个this就是retrofit对象。

      我们再来关注OKHttpCall:

      1. final class OkHttpCall implements Call {
      2. private final ServiceMethod serviceMethod;
      3. private final @Nullable Object[] args;
      4. private volatile boolean canceled;
      5. @GuardedBy("this")
      6. private @Nullable okhttp3.Call rawCall;
      7. @GuardedBy("this")
      8. private @Nullable Throwable creationFailure; // Either a RuntimeException or IOException.
      9. @GuardedBy("this")
      10. private boolean executed;
      11. OkHttpCall(ServiceMethod serviceMethod, @Nullable Object[] args) {
      12. this.serviceMethod = serviceMethod;
      13. this.args = args;
      14. }
      15. ···
      16. @Override public void enqueue(final Callback callback) {
      17. checkNotNull(callback, "callback == null");
      18. okhttp3.Call call;
      19. Throwable failure;
      20. synchronized (this) {
      21. if (executed) throw new IllegalStateException("Already executed.");
      22. executed = true;
      23. call = rawCall;
      24. failure = creationFailure;
      25. if (call == null && failure == null) {
      26. try {
      27. call = rawCall = createRawCall();
      28. } catch (Throwable t) {
      29. failure = creationFailure = t;
      30. }
      31. }
      32. }
      33. if (failure != null) {
      34. callback.onFailure(this, failure);
      35. return;
      36. }
      37. if (canceled) {
      38. call.cancel();
      39. }
      40. call.enqueue(new okhttp3.Callback() {
      41. @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
      42. throws IOException {
      43. Response response;
      44. try {
      45. response = parseResponse(rawResponse);
      46. } catch (Throwable e) {
      47. callFailure(e);
      48. return;
      49. }
      50. callSuccess(response);
      51. }
      52. @Override public void onFailure(okhttp3.Call call, IOException e) {
      53. try {
      54. callback.onFailure(OkHttpCall.this, e);
      55. } catch (Throwable t) {
      56. t.printStackTrace();
      57. }
      58. }
      59. private void callFailure(Throwable e) {
      60. try {
      61. callback.onFailure(OkHttpCall.this, e);
      62. } catch (Throwable t) {
      63. t.printStackTrace();
      64. }
      65. }
      66. private void callSuccess(Response response) {
      67. try {
      68. callback.onResponse(OkHttpCall.this, response);
      69. } catch (Throwable t) {
      70. t.printStackTrace();
      71. }
      72. }
      73. });
      74. }
      75. @Override public synchronized boolean isExecuted() {
      76. return executed;
      77. }
      78. private okhttp3.Call createRawCall() throws IOException {
      79. Request request = serviceMethod.toRequest(args);
      80. okhttp3.Call call = serviceMethod.callFactory.newCall(request);
      81. if (call == null) {
      82. throw new NullPointerException("Call.Factory returned null.");
      83. }
      84. return call;
      85. }
      86. Response parseResponse(okhttp3.Response rawResponse) throws IOException {
      87. ResponseBody rawBody = rawResponse.body();
      88. // Remove the body's source (the only stateful object) so we can pass the response along.
      89. rawResponse = rawResponse.newBuilder()
      90. .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
      91. .build();
      92. int code = rawResponse.code();
      93. if (code < 200 || code >= 300) {
      94. try {
      95. // Buffer the entire body to avoid future I/O.
      96. ResponseBody bufferedBody = Utils.buffer(rawBody);
      97. return Response.error(bufferedBody, rawResponse);
      98. } finally {
      99. rawBody.close();
      100. }
      101. }
      102. if (code == 204 || code == 205) {
      103. rawBody.close();
      104. return Response.success(null, rawResponse);
      105. }
      106. ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
      107. try {
      108. T body = serviceMethod.toResponse(catchingBody);
      109. return Response.success(body, rawResponse);
      110. } catch (RuntimeException e) {
      111. // If the underlying source threw an exception, propagate that rather than indicating it was
      112. // a runtime exception.
      113. catchingBody.throwIfCaught();
      114. throw e;
      115. }
      116. }
      117. ···
      118. }

      我们发现,内部创建了一个OkHttp的call,执行的也是OkHttp创建的call的异步方法,这里也可以看出来Retrofit的网络请求其实是交给OkHttp来处理的。我们再来关注一下这段代码:

      1. private void callSuccess(Response response) {
      2. try {
      3. callback.onResponse(OkHttpCall.this, response);
      4. } catch (Throwable t) {
      5. t.printStackTrace();
      6. }
      7. }

      这个时候线程还没有切换,那么这个callback又是什么呢?我们看下面一段代码:

      1. final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
      2. final Executor callbackExecutor;
      3. ExecutorCallAdapterFactory(Executor callbackExecutor) {
      4. this.callbackExecutor = callbackExecutor;
      5. }
      6. @Override
      7. public CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
      8. if (getRawType(returnType) != Call.class) {
      9. return null;
      10. }
      11. final Type responseType = Utils.getCallResponseType(returnType);
      12. return new CallAdapter>() {
      13. @Override public Type responseType() {
      14. return responseType;
      15. }
      16. @Override public Call adapt(Call call) {
      17. return new ExecutorCallbackCall<>(callbackExecutor, call);
      18. }
      19. };
      20. }
      21. static final class ExecutorCallbackCall implements Call {
      22. final Executor callbackExecutor;
      23. final Call delegate;
      24. ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
      25. this.callbackExecutor = callbackExecutor;
      26. this.delegate = delegate;
      27. }
      28. @Override public void enqueue(final Callback callback) {
      29. checkNotNull(callback, "callback == null");
      30. delegate.enqueue(new Callback() {//注释1
      31. @Override public void onResponse(Call call, final Response response) {
      32. callbackExecutor.execute(new Runnable() {
      33. @Override public void run() {
      34. if (delegate.isCanceled()) {
      35. // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
      36. callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
      37. } else {
      38. callback.onResponse(ExecutorCallbackCall.this, response);
      39. }
      40. }
      41. });
      42. }
      43. @Override public void onFailure(Call call, final Throwable t) {
      44. callbackExecutor.execute(new Runnable() {
      45. @Override public void run() {
      46. callback.onFailure(ExecutorCallbackCall.this, t);
      47. }
      48. });
      49. }
      50. });
      51. }
      52. @Override public boolean isExecuted() {
      53. return delegate.isExecuted();
      54. }
      55. @Override public Response execute() throws IOException {
      56. return delegate.execute();
      57. }
      58. @Override public void cancel() {
      59. delegate.cancel();
      60. }
      61. @Override public boolean isCanceled() {
      62. return delegate.isCanceled();
      63. }
      64. @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
      65. @Override public Call clone() {
      66. return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
      67. }
      68. @Override public Request request() {
      69. return delegate.request();
      70. }
      71. }
      72. }
      73. 这个delegate就是OkHttpCall,我们传了一个实现CallBack接口的对象进去。接着来看onResponse方法,关注callbackExecutor,这又是个什么东西呢?不着急我们一点一点分析。

        我们回过头来再看这一行代码:

        serviceMethod.callAdapter.adapt(okHttpCall)

        顺着这一行代码往下推:这个callAdapter是个啥?

        1. public ServiceMethod build() {
        2. callAdapter = createCallAdapter();
        3. ```
        4. }
        1. private CallAdapter createCallAdapter() {
        2. Type returnType = method.getGenericReturnType();
        3. if (Utils.hasUnresolvableType(returnType)) {
        4. throw methodError(
        5. "Method return type must not include a type variable or wildcard: %s", returnType);
        6. }
        7. if (returnType == void.class) {
        8. throw methodError("Service methods cannot return void.");
        9. }
        10. Annotation[] annotations = method.getAnnotations();
        11. try {
        12. //noinspection unchecked
        13. return (CallAdapter) retrofit.callAdapter(returnType, annotations);
        14. } catch (RuntimeException e) { // Wide exception range because factories are user code.
        15. throw methodError(e, "Unable to create call adapter for %s", returnType);
        16. }
        17. }

        调用了retrofit的callAdapter方法:

        1. public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {
        2. return nextCallAdapter(null, returnType, annotations);
        3. }
        4. /**
        5. * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
        6. * #callAdapterFactories() factories} except {@code skipPast}.
        7. *
        8. * @throws IllegalArgumentException if no call adapter available for {@code type}.
        9. */
        10. public CallAdapter nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
        11. Annotation[] annotations) {
        12. checkNotNull(returnType, "returnType == null");
        13. checkNotNull(annotations, "annotations == null");
        14. int start = adapterFactories.indexOf(skipPast) + 1;
        15. for (int i = start, count = adapterFactories.size(); i < count; i++) {
        16. CallAdapter adapter = adapterFactories.get(i).get(returnType, annotations, this);//注释处
        17. if (adapter != null) {
        18. return adapter;
        19. }
        20. }
        21. StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        22. .append(returnType)
        23. .append(".\n");
        24. if (skipPast != null) {
        25. builder.append(" Skipped:");
        26. for (int i = 0; i < start; i++) {
        27. builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
        28. }
        29. builder.append('\n');
        30. }
        31. builder.append(" Tried:");
        32. for (int i = start, count = adapterFactories.size(); i < count; i++) {
        33. builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
        34. }
        35. throw new IllegalArgumentException(builder.toString());
        36. }

        注意一下注释处:我们从adapterFactories里面去拿,那么callAdapter什么时候加入这个集合的呢?

        1. Executor callbackExecutor = this.callbackExecutor;
        2. if (callbackExecutor == null) {
        3. callbackExecutor = platform.defaultCallbackExecutor();
        4. }
        5. // Make a defensive copy of the adapters and add the default Call adapter.
        6. List adapterFactories = new ArrayList<>(this.adapterFactories);
        7. adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
        8. static class Android extends Platform {
        9. @Override public Executor defaultCallbackExecutor() {
        10. return new MainThreadExecutor();
        11. }
        12. @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        13. if (callbackExecutor == null) throw new AssertionError();
        14. return new ExecutorCallAdapterFactory(callbackExecutor);
        15. }
        16. static class MainThreadExecutor implements Executor {
        17. private final Handler handler = new Handler(Looper.getMainLooper());
        18. @Override public void execute(Runnable r) {
        19. handler.post(r);
        20. }
        21. }
        22. }

        终于找到了ExecutorCallAdapterFactory!这样跟前面结合起来就形成了一个完美的闭环不是吗?

        我们最后再来理一理这个逻辑,可能还是有很多同学不是很明白:

        Retrofit的Call调用enqueue方法,其实是ExecutorCallAdapterFactory的内部类ExecutorCallbackCall的enqueue方法,而这个方法其实调用了OkHttpCall的enqueue方法,而OkHttpCall的enqueue方法执行的是OKHttp的Call得enqueue方法。线程切换就是在callbackExecutor.execute这里完成的,这个callbackExecutor其实是一个MainThreadExecutor(),内部封装了一个Handler,实现了线程切换。

      74. 相关阅读:
        【使用教程】在Ubuntu下PMM60系列一体化伺服电机通过PDO跑循环同步位置模式详解
        嵌入式系统软件层次结构
        (七)admin-boot项目之全局处理字符串两边空格
        【Mysql】第4篇--多表查询和事务
        【SQL注入】关于GORM的SQL注入问题
        Ardupilot开源飞控之AP_Follow
        grafana 通过查询结果设置动态阈值
        Angular:通过路由切换页面后,ngOnInit()不会被触发的问题
        Keepalived+LVS高可用集群
        蓝桥杯练习题
      75. 原文地址:https://blog.csdn.net/qq_36428821/article/details/126878878
        • 最新文章
        • 攻防演习之三天拿下官网站群
          数据安全治理学习——前期安全规划和安全管理体系建设
          企业安全 | 企业内一次钓鱼演练准备过程
          内网渗透测试 | Kerberos协议及其部分攻击手法
          0day的产生 | 不懂代码的"代码审计"
          安装scrcpy-client模块av模块异常,环境问题解决方案
          leetcode hot100【LeetCode 279. 完全平方数】java实现
          OpenWrt下安装Mosquitto
          AnatoMask论文汇总
          【AI日记】24.11.01 LangChain、openai api和github copilot
        • 热门文章
        • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
          奉劝各位学弟学妹们,该打造你的技术影响力了!
          五年了,我在 CSDN 的两个一百万。
          Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
          面试官都震惊,你这网络基础可以啊!
          你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
          心情不好的时候,用 Python 画棵樱花树送给自己吧
          通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
          13 万字 C 语言从入门到精通保姆级教程2021 年版
          10行代码集2000张美女图,Python爬虫120例,再上征途
        Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
        正则表达式工具 cron表达式工具 密码生成工具

        京公网安备 11010502049817号