zoukankan      html  css  js  c++  java
  • Retrofit源码解析(下)

    接着上一章继续分析上一章主要简单说了一下基本使用和注解,这一章,我们主要看源码,废话不多说了,直接上。先上一张图 从网络上拿来的

    前面一章说了一下Retrofit的简单使用https://www.cnblogs.com/huangjialin/p/9492182.html

     1     //创建retrofit
     2         Retrofit retrofit = new Retrofit.Builder()
     3                 .baseUrl(url) //设置baseURl
     4                 .addConverterFactory(ScalarsConverterFactory.create()) //增加返回值为String的支持
     5                 .addConverterFactory(GsonConverterFactory.create())
     6                 .build();
     7         ApiService apiService = retrofit.create(ApiService.class);
     8         Call<SwitchTest> call = apiService.getInformation();
     9         call.enqueue(new Callback<SwitchTest>() {
    10             @Override
    11             public void onResponse(Call<SwitchTest> call, Response<SwitchTest> response) {
    12                 Log.d("huangjialin", "---onResponse----" + response.body().getMessage());
    13             }
    14 
    15             @Override
    16             public void onFailure(Call<SwitchTest> call, Throwable t) {
    17                 Log.d("huangjialin", "--- 失败----" );
    18 
    19             }
    20         });

    我们看一下new Retrofit.Builder()源码是怎么走的

    1 public Builder() {
    2       this(Platform.get());
    3     }
     1 class Platform {
     2   private static final Platform PLATFORM = findPlatform();
     3 
     4   static Platform get() {
     5     return PLATFORM;
     6   }
     7 
     8   private static Platform findPlatform() {
     9     try {
    10       Class.forName("android.os.Build");
    11       if (Build.VERSION.SDK_INT != 0) {
    12         return new Android();
    13       }
    14     } catch (ClassNotFoundException ignored) {
    15     }
    16     try {
    17       Class.forName("java.util.Optional");
    18       return new Java8();
    19     } catch (ClassNotFoundException ignored) {
    20     }
    21     return new Platform();
    22   }
    23 //—————省略若干代码—————-
    24 }

    从代码中可以看出来,Builder后先是调用this(Platform.get());然后在调用findPlatform()方法,在findPlatform()方法中主要进行平台的判断,不同的平台返回不同的线程池。在最新的几个版本中去掉了iOS平台的判断。
    好了,回过头来我们接着看build()方法是怎么执行的

     1 public Retrofit build() {
     2       if (baseUrl == null) { //从这里这里知道baseUrl一定不能为空,也就是说必须要设置,否则会抛异常
     3         throw new IllegalStateException("Base URL required.");
     4       }
     5 
     6       okhttp3.Call.Factory callFactory = this.callFactory; //如果需要对OkHttpClient进行设置,则可以构建OkHttpClient对象,然后调用callFactory方法将设置好的OkHttpClient传进去。
     7       if (callFactory == null) {
     8         callFactory = new OkHttpClient();
     9       }
    10 
    11       Executor callbackExecutor = this.callbackExecutor;
    12       if (callbackExecutor == null) {
    13         callbackExecutor = platform.defaultCallbackExecutor(); //将回调传递到主线程
    14       }
    15 
    16       // adapterFactories主要用于存储对Call进行转化的对象
    17       List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    18       callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    19 
    20       //主要用于存储数据转换后的对象 
    21       List<Converter.Factory> converterFactories =
    22           new ArrayList<>(1 + this.converterFactories.size());
    23 
    24       // Add the built-in converter factory first. This prevents overriding its behavior but also
    25       // ensures correct behavior when using converters that consume all types.
    26       converterFactories.add(new BuiltInConverters());
    27       converterFactories.addAll(this.converterFactories);
    28 
    29       //将retrofit对象返回来
    30       return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
    31           unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    32     }

    上面做的注释很清晰,也就是说build()后,我们可以拿到这个Retrofit这个对象,接着ApiService apiService = retrofit.create(ApiService.class);我们看看这句代码的源码是怎么走的

     1 public <T> T create(final Class<T> service) {
     2     //这里主要是进行一些判断验证,比如说我们这里定义的ApiService,这个只能定义为interfaces类型,而不能定义为class类型。并且interfaces不能被扩展
     3     Utils.validateServiceInterface(service); 
     4     if (validateEagerly) {
     5       eagerlyValidateMethods(service);
     6     }
     7     return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
     8         new InvocationHandler() {
     9           private final Platform platform = Platform.get();
    10 
    11           @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
    12               throws Throwable {
    13             // 判断方法是不是属于对象的方法
    14             if (method.getDeclaringClass() == Object.class) {
    15               return method.invoke(this, args);
    16             }
    17             //判断是否在主线程
    18             if (platform.isDefaultMethod(method)) {
    19               return platform.invokeDefaultMethod(method, service, proxy, args);
    20             }
    21             ServiceMethod<Object, Object> serviceMethod =
    22                 (ServiceMethod<Object, Object>) loadServiceMethod(method);
    23             OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    24             return serviceMethod.adapt(okHttpCall);
    25           }
    26         });
    27   }

    当进行一系列验证判断以后,Proxy.newProxyInstance来拿到一个动态代理,同时实现invoke()方法。通过当我们调用接口中的方法时,比如说调用登陆接口 Call<LoginModel> login(@Body Login login);,
    这个时候就会调用InvocationHandler中的invoke方法,invoke()方法中有三个参数,第一个就是代理对象,第二个就是所调用的方法,比如说调用登陆接口,这个方法就是login,第三个就是方法参数了。
    接着我们找到loadServiceMethod(method)我们看看是怎么执行的。

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

    loadServiceMethod这个方法,首先进行一下判断,也就是说先从缓存中获取,看看缓存中有没有这个请求方法,如果有的话,那就直接返回,没有的话,通过new ServiceMethod.Builder<>(this, method).build();
    来构建,然后在保存起来。我们看看build()中的源码

     1  public ServiceMethod build() {
     2  //调用了createCallAdapter方法,它最终会得到我们在构建Retrofit调用build方法时adapterFactories添加的对象的get方法
     3       callAdapter = createCallAdapter();
     4       //获取到返回数据的类型
     5       responseType = callAdapter.responseType();
     6       if (responseType == Response.class || responseType == okhttp3.Response.class) {
     7         throw methodError("'"
     8             + Utils.getRawType(responseType).getName()
     9             + "' is not a valid response body type. Did you mean ResponseBody?");
    10       }
    11       //这里面通过遍历来拿到我们适合的Converter的转化对象,由于retrofit可以调用addConverterFactory添加多个,如Gson
    12       responseConverter = createResponseConverter();
    13 
    14       //这里主要是通过遍历拿到请求请求方法,如GET POST ,PUT这些
    15       for (Annotation annotation : methodAnnotations) {
    16         parseMethodAnnotation(annotation);
    17       }
    18 
    19       //这里主要进行一下判断,就是如果没有请求方法的话,就会抛出异常
    20       if (httpMethod == null) {
    21         throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
    22       }
    23 
    24       if (!hasBody) {
    25         if (isMultipart) {
    26           throw methodError(
    27               "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    28         }
    29         if (isFormEncoded) {
    30           throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
    31               + "request body (e.g., @POST).");
    32         }
    33       }
    34 
    35       int parameterCount = parameterAnnotationsArray.length;
    36       parameterHandlers = new ParameterHandler<?>[parameterCount];
    37       for (int p = 0; p < parameterCount; p++) {
    38         Type parameterType = parameterTypes[p];
    39         if (Utils.hasUnresolvableType(parameterType)) {
    40           throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
    41               parameterType);
    42         }
    43 
    44         //这里获取到我们接口上面的参数注解比如说@Query @QueryMap这些
    45         Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    46         if (parameterAnnotations == null) {
    47           throw parameterError(p, "No Retrofit annotation found.");
    48         }
    49 
    50         parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
    51       }
    52 
    53       if (relativeUrl == null && !gotUrl) {
    54         throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
    55       }
    56       if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    57         throw methodError("Non-body HTTP method cannot contain @Body.");
    58       }
    59       if (isFormEncoded && !gotField) {
    60         throw methodError("Form-encoded method must contain at least one @Field.");
    61       }
    62       if (isMultipart && !gotPart) {
    63         throw methodError("Multipart method must contain at least one @Part.");
    64       }
    65 
    66       //返回ServiceMethod对象
    67       return new ServiceMethod<>(this);
    68     }

    上面这个方法主要目的就是为了拿到ServiceMethod对象。回过头来,我们继续看retrofit的create()方法

    1 ServiceMethod<Object, Object> serviceMethod =
    2             (ServiceMethod<Object, Object>) loadServiceMethod(method);
    3             OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

    当拿到serviceMethod对象以后,接着就执行new OkHttpCall();来得到okHttpCall,并且最后返回serviceMethod.adapt(okHttpCall),我们进入OkHttpCall()对象看看

     1 final class OkHttpCall<T> implements Call<T> {
     2 
     3   //------省略若干代码--------
     4 
     5   @Override public synchronized Request request() {
     6     okhttp3.Call call = rawCall;
     7     if (call != null) {
     8       return call.request();
     9     }
    10     if (creationFailure != null) {
    11       if (creationFailure instanceof IOException) {
    12         throw new RuntimeException("Unable to create request.", creationFailure);
    13       } else if (creationFailure instanceof RuntimeException) {
    14         throw (RuntimeException) creationFailure;
    15       } else {
    16         throw (Error) creationFailure;
    17       }
    18     }
    19     try {
    20       return (rawCall = createRawCall()).request();
    21     } catch (RuntimeException | Error e) {
    22       throwIfFatal(e); // Do not assign a fatal error to creationFailure.
    23       creationFailure = e;
    24       throw e;
    25     } catch (IOException e) {
    26       creationFailure = e;
    27       throw new RuntimeException("Unable to create request.", e);
    28     }
    29   }
    30 
    31   @Override public void enqueue(final Callback<T> callback) {
    32     checkNotNull(callback, "callback == null");
    33 
    34     okhttp3.Call call;
    35     Throwable failure;
    36 
    37     synchronized (this) {
    38       if (executed) throw new IllegalStateException("Already executed.");
    39       executed = true;
    40 
    41       call = rawCall;
    42       failure = creationFailure;
    43       if (call == null && failure == null) {
    44         try {
    45           call = rawCall = createRawCall();
    46         } catch (Throwable t) {
    47           throwIfFatal(t);
    48           failure = creationFailure = t;
    49         }
    50       }
    51     }
    52 
    53     if (failure != null) {
    54       callback.onFailure(this, failure);
    55       return;
    56     }
    57 
    58     if (canceled) {
    59       call.cancel();
    60     }
    61 
    62     call.enqueue(new okhttp3.Callback() {
    63       @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
    64         Response<T> response;
    65         try {
    66           response = parseResponse(rawResponse);
    67         } catch (Throwable e) {
    68           callFailure(e);
    69           return;
    70         }
    71 
    72         try {
    73           callback.onResponse(OkHttpCall.this, response);
    74         } catch (Throwable t) {
    75           t.printStackTrace();
    76         }
    77       }
    78 
    79       @Override public void onFailure(okhttp3.Call call, IOException e) {
    80         callFailure(e);
    81       }
    82 
    83       private void callFailure(Throwable e) {
    84         try {
    85           callback.onFailure(OkHttpCall.this, e);
    86         } catch (Throwable t) {
    87           t.printStackTrace();
    88         }
    89       }
    90     });
    91   }
    92   
    93 //  --------省略若干代码---------

    到这里,基本很明了,看过我前面的okhttp源码解析的朋友,这里就会觉得很熟悉了,这里通过实现 Call接口,然后通过request()和enqueue()这两个方法,然后将请求的结果回调回来,从而实现网络通信。
    当然,这里只是retrofit一些基本的流程在源码中是这样走的,如果说要非常非常详细的源码,这不是一两篇文章能写完的,光retrofit就可以写出一本书了,当然,目前的水平,还没有达到那个地步,慢慢来。

  • 相关阅读:
    dp的小理解
    POJ
    isolate-user-vlan隔离用户vlan的配置
    【mvrp多协议vlan注册协议给予三种注册方式的验证】
    【Commare中关于理论范畴和技术常用的技术术语】
    BGP映射和联盟
    filter-policy和AS-PATH-FILTER过滤BGP路由条目
    【路由过滤工具小结】
    【ISIS(中间系统到中间系统)路由链路状态信息协议初识】
    【poe设备加电配置】
  • 原文地址:https://www.cnblogs.com/huangjialin/p/9492271.html
Copyright © 2011-2022 走看看