Android Retrofit源码分析(一边用一边侃)

Posted 冒泡的章鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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     }

 

    待续

 

 

 

 

 

 

 

 

 




以上是关于Android Retrofit源码分析(一边用一边侃)的主要内容,如果未能解决你的问题,请参考以下文章

Android Retrofit 源码系列~ 设计模式分析

[Android] Retrofit 源码分析之 ServiceMethod 对象

[Android] Retrofit 源码分析之 ServiceMethod 对象

Android实战----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)

Android实战----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的

[Android] Retrofit 执行流程源码分析