zoukankan      html  css  js  c++  java
  • Android Retrofit源码分析(一边用一边侃)

      这几天空余时间总是想着写点什么,所以紧跟着之前android盒子模型FlexBoxLayout之后有写下了这篇Retrofit源码分析使用篇。

      前言:

        Retrofit由于简单与出色的性能,使其安卓上最流行的HTTP Client库之一。

      Android Studio开发相关配置如下:

    compile "com.squareup.retrofit2:retrofit:2.0.2"
    compile "com.squareup.retrofit2:converter-gson:2.0.2"

      这里仅仅是简单的说明下使用,不会过多的讲解说明作用,原因就是类似使用文章百度可谓是一堆堆(杂乱无章)

            OkHttpClient client = new OkHttpClient();
            client.networkInterceptors().add(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Response response = chain.proceed(chain.request());
                    /*添加需要过滤的请求*/
                    return response;
                }
            });

      上述代码代码只有在有需要过滤特殊的网络请求时才有必要,否则可以不用理睬,往下看。

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://api.nuuneoi.com/base/")
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

      这里涉及Retrofit的创造和参数的构建,这里回答下上边说道的为什么在不需要进行相应的参数过滤的时候,可以不用指定对应的Client,让我看下源码内部实现:

     1 /**
     2      * Create the {@link Retrofit} instance using the configured values.
     3      * <p>
     4      * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
     5      * OkHttpClient} will be created and used.
     6      */
     7     public Retrofit build() {
     8       if (baseUrl == null) {
     9         throw new IllegalStateException("Base URL required.");
    10       }
    11 
    12       okhttp3.Call.Factory callFactory = this.callFactory;
    13       if (callFactory == null) {
    14         callFactory = new OkHttpClient();
    15       }
    16 
    17       Executor callbackExecutor = this.callbackExecutor;
    18       if (callbackExecutor == null) {
    19         callbackExecutor = platform.defaultCallbackExecutor();
    20       }
    21 
    22       // Make a defensive copy of the adapters and add the default Call adapter.
    23       List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    24       adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    25 
    26       // Make a defensive copy of the converters.
    27       List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    28 
    29       return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
    30           callbackExecutor, validateEagerly);
    31     }

      这里是Retrofit内部builder构建类进行build时候执行的方法,这里稍稍关注下行12-15,判断是否callFactory是否为空,那么callFactory对象来自哪里哪?咱们继续深入源码。

    /**
         * Specify a custom call factory for creating {@link Call} instances.
         * <p>
         * Note: Calling {@link #client} automatically sets this value.
         */
        public Builder callFactory(okhttp3.Call.Factory factory) {
          this.callFactory = checkNotNull(factory, "factory == null");
          return this;
        }

      这里是给callFactory对象赋值的地方,那我在看谁调用了这个方法。

    /**
         * The HTTP client used for requests.
         * <p>
         * This is a convenience method for calling {@link #callFactory}.
         * <p>
         * Note: This method <b>does not</b> make a defensive copy of {@code client}. Changes to its
         * settings will affect subsequent requests. Pass in a {@linkplain OkHttpClient#clone() cloned}
         * instance to prevent this if desired.
         */
        public Builder client(OkHttpClient client) {
          return callFactory(checkNotNull(client, "client == null"));
        }

      很显然这里就是我们在初始化Retrofit的时候添加OkHttpClient的地方。这也就是刚才说的为什么但咱们不需要过滤网络请求可以不添加OkHttpClient

      

      这里需要大家稍微记下是ConverterFactory,他的作用是对返回的数据格式化。

      这里之所以说道这块以防你需要调整json里面的一些格式,比如,Date Format。你可以创建一个Gson 对象并把它传递给GsonConverterFactory.create(),遇到类似问题可以参考如下处理方式

    son gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .create();
    
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("")
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

      紧接着让我们跟着上边的简单使用来全面走进源码,一窥内部实现方式。

        1、这里需要优先记忆的几个对象声明如下:

        callFactory:这个参数代表是实现了Call.Factory接口的类的实例,其实也就是OkHttpClient

         converterFactories:返回数据格式化类,也就是GonsConverterFactory

        adapterFactories:这个集合对象内部是CallAdapter.Factory接口实现类的实例对象

      根据上述的简单使用我们了解到,Retrofit在创建的时候需要传入一个字节码文件,这里姑且不说这个字节码文件是类还是接口,咱们看下源码内部设计。

     1 @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
     2   public <T> T create(final Class<T> service) {
     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, 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             if (platform.isDefaultMethod(method)) {
    18               return platform.invokeDefaultMethod(method, service, proxy, args);
    19             }
    20             ServiceMethod serviceMethod = loadServiceMethod(method);
    21             OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
    22             return serviceMethod.callAdapter.adapt(okHttpCall);
    23           }
    24         });
    25   }

      大家注意下方法内部第3行,Utils.validateServiceInterface(service),这里直接翻译就是是否是有效的服务接口,看名字可能有些人会一下不是很明白,让我看下改方法实现。

     1   static <T> void validateServiceInterface(Class<T> service) {
     2     if (!service.isInterface()) {
     3       throw new IllegalArgumentException("API declarations must be interfaces.");
     4     }
     5     // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
     6     // Android (http://b.android.com/58753) but it forces composition of API declarations which is
     7     // the recommended pattern.
     8     if (service.getInterfaces().length > 0) {
     9       throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    10     }
    11   }

      直译代码行2,意思是传入的字节码文件是是否是接口,如果不是则抛出一个非法参数异常,这是其一。行8看到该接口是否继承自其它接口,也就是说该接口不允许采用继承的方式。到这里咱们总结了两点  

      RetrofitCreate方法传入的字节码文件要求如下:

        必须是一个接口

        该接口不能继承其他接口

     2、这里还是create方法的使用,那么接下来我们来看看他们是如何使用接口,完成一系列的网络请求的。

        这里首先我们在回到刚才的Create方法中,看下Create方法对应的返回值

     1 ......
     2 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
     3         new InvocationHandler() {
     4           private final Platform platform = Platform.get();
     5 
     6           @Override public Object invoke(Object proxy, Method method, Object... args)
     7               throws Throwable {
     8             // If the method is a method from Object then defer to normal invocation.
     9             if (method.getDeclaringClass() == Object.class) {
    10               return method.invoke(this, args);
    11             }
    12             if (platform.isDefaultMethod(method)) {
    13               return platform.invokeDefaultMethod(method, service, proxy, args);
    14             }
    15             ServiceMethod serviceMethod = loadServiceMethod(method);
    16             OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
    17             return serviceMethod.callAdapter.adapt(okHttpCall);
    18           }
    19         });
    20 ......

      这里使用到java中高级部分篇章java的动态代理,简单点来说也就是当你调用接口中对应的方法会优先调用InvocationHandler中的invoke方法,有不是很明白的童鞋可行百度了解这块技术,这里就不在深入介绍。

      知道动态代理的基本流程,让我们看下invoke方法内部究竟是如何工作的。

      2.1、行4,这里根据不同的平台返回不同的Platform platform = Platform.get()对象

      2.2、行9-11,这里是判断调用的方式是否是Object里的方法,如果是则直接调用不做处理.

      2.3、行12-14,这里仅仅是java8才会使用

      2.4、行15,这里还是封装method方法,并且处理对应的注解生成指定的请求头和请求体.

      2.5、行16,okHttpCall真正的请求实现类

      2.6、行17,返回对应封装了指定数据类型的Call

      2.1、精讲说明

     1  private static final Platform PLATFORM = findPlatform();
     2 
     3   static Platform get() {
     4     return PLATFORM;
     5   }
     6 
     7   private static Platform findPlatform() {
     8     try {
     9       Class.forName("android.os.Build");
    10       if (Build.VERSION.SDK_INT != 0) {
    11         return new Android();
    12       }
    13     } catch (ClassNotFoundException ignored) {
    14     }
    15     try {
    16       Class.forName("java.util.Optional");
    17       return new Java8();
    18     } catch (ClassNotFoundException ignored) {
    19     }
    20     try {
    21       Class.forName("org.robovm.apple.foundation.NSObject");
    22       return new IOS();
    23     } catch (ClassNotFoundException ignored) {
    24     }
    25     return new Platform();
    26   }

      2.1.1、这里调用Platform的静态方法get(),然后调用方法findPlatform()

      2.1.2、方法findPlatform()根据不同的平台返回不同的对象,这里咱们使用的Android,所以返回的是Android对象

      Android类对象继承Platform类,源码如下:

     1  static class Android extends Platform {
     2     @Override public Executor defaultCallbackExecutor() {
     3       return new MainThreadExecutor();
     4     }
     5 
     6     @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
     7       return new ExecutorCallAdapterFactory(callbackExecutor);
     8     }
     9 
    10     static class MainThreadExecutor implements Executor {
    11       private final Handler handler = new Handler(Looper.getMainLooper());
    12 
    13       @Override public void execute(Runnable r) {
    14         handler.post(r);
    15       }
    16     }
    17   }

      如上代码可以知道,

        1、Android继承自类Platform,重载了Platform方法defaultCallbackExecutordefaultCallAdapterFactory,方法defaultCallbackExecutor返回一个MainThreadExecutor对象,方法defaultCallAdapterFactory返回了一个对象ExecutorCallAdapterFactory

        2、声明静态内部类MainThreadExecutor实现了接口Executor,同时初始化了一个Handler对象。

      

      2.2、精讲说明<判断调用的方式是否是Object里的方法,如果是则直接调用不做处理.>  

        由于不涉及Retrofit的相关操作,这里不再进行说明。

      2.3、精讲说明<这里仅仅是java8才会使用>  

         为什么这么说那,关键在于代码platform.isDefaultMethod(method),所以想说明白这个问题我们还是需要在进一步看下方法isDefaultMethod,当然前边我说道platform返回的是Android,所以这里先从类Android看。上边说道Platform重载了Platform方法defaultCallbackExecutordefaultCallAdapterFactory,所以这里仅仅需要看下platform类对该方法的处理即可。

      boolean isDefaultMethod(Method method) {
        return false;
      }

        默认返回是false,很显然Android平台并不会进入逻辑处理,那么既然说道java8才会使用那么必然java类重载了该方法,深入源码我们看下。

     static class Java8 extends Platform {
        @Override boolean isDefaultMethod(Method method) {
          return method.isDefault();
        }
      }

        正如我们想象的那样。

        2.4、精讲说明<这里还是封装method方法,并且处理对应的注解生成指定的请求头和请求体.>  

          这里我们先跟着代码一起往下看loadServiceMethod(method)

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

         这里对method和对应的ServiceMethod做了缓存,这里优先判断缓存,如果不存在则去new一个ServiceMethod对象。继续看ServiceMethod对象创建的过程。

         类Builder构造器

    1 public Builder(Retrofit retrofit, Method method) {
    2       this.retrofit = retrofit;
    3       this.method = method;
    4       this.methodAnnotations = method.getAnnotations();
    5       this.parameterTypes = method.getGenericParameterTypes();
    6       this.parameterAnnotationsArray = method.getParameterAnnotations();
    7     }

        待续

    
    
  • 相关阅读:
    针对安卓java入门:方法的使用
    ES6里关于字符串的拓展
    ES6里关于数字的拓展
    项目笔记:导出XML和导出全部XML功能
    项目笔记:中文转拼音工具类
    深入理解dataset及其用法
    前端插件实现图片懒加载
    Java里日期转换及日期比较大小
    iframe.contentWindow 属性:关于contentWindow和contentDocument区分
    GROUP BY 和 GROUP_CONCAT的使用
  • 原文地址:https://www.cnblogs.com/liemng/p/7515667.html
Copyright © 2011-2022 走看看