美文网首页Android学习日记
Android日记之Retrofit源码解析

Android日记之Retrofit源码解析

作者: 居居居居居居x | 来源:发表于2019-10-19 21:10 被阅读0次

    前言

    别问我为啥先写Retrofit的源码解析而不是okhttp的源码解析,主要是最近这几次面试Retrofit被问到的比例相当的大,所以就先写Retrofit的(其实主要是okhttp在项目上已经用上了,面试官也就懒得问了-_-||),我们老样子,从怎么使用这个框架的地方开始入手源码,Retrofit的使用方法可以看Android日记之Retrofit初探,这里的Retrofit版本是2.5。

    Retrofit的构建

    Retrofit的Builder()方法

    public static final class Builder {
        private final Platform platform;
        private @Nullable okhttp3.Call.Factory callFactory;
        private @Nullable HttpUrl baseUrl;
        private final List<Converter.Factory> converterFactories = new ArrayList<>();
        private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
        private @Nullable Executor callbackExecutor;
        private boolean validateEagerly;
    
        Builder(Platform platform) {
          this.platform = platform;
        }
    
        public Builder() {
          this(Platform.get());
        }
        
        ......
    }
    
    class Platform {
      private static final Platform PLATFORM = findPlatform();
    
      static Platform get() {
        return PLATFORM;
      }
    
      private static Platform findPlatform() {
        try {
          Class.forName("android.os.Build");
          if (Build.VERSION.SDK_INT != 0) {
            return new Android();
          }
        } catch (ClassNotFoundException ignored) {
        }
        try {
          Class.forName("java.util.Optional");
          return new Java8();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
      }
      
      ......
    }
    

    里面主要多了一个Platform,它其实是一个很重要的东西,主要是调用了Platform的get()方法来进行赋值,然后调用里面的findPlatform()方法,这里面主要就是看你是哪个平台的,通过Class.forName来查找指定的类,然后返回一个Android对象(在Android使用肯定是这个的啦),至于这个Android里面主要干了什么,看了下源码,只知道是跟Retrofit要构建的变量Executor有关,看了下其他论坛的讲解,迷迷糊糊的,还是看不懂,以后再看-_-||。

    Retrofit的build()方法

    //创建Retrfit
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://wanandroid.com/wxarticle/chapters/json/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    
    //build方法源码
    public Retrofit build() {
        //这里说明一定需要baseUrl。
        throw new IllegalStateException("Base URL required.");
        }
    
        //这里判断如果没有callFactory的话,就会创建一个OkHttpClient()。
        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null) {
        callFactory = new OkHttpClient();
        }
    
        //也是一样,如果没有callbackExecutor,就会设置成默认配置defaultCallbackExecutor。
        Executor callbackExecutor = this.callbackExecutor;
        if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
        }
        
        //这里说明会把defaultCallAdapterFactories配置添加到List里面去
        // Make a defensive copy of the adapters and add the default Call adapter.
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
        callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    
        // Make a defensive copy of the converters.
        List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    
        // Add the built-in converter factory first. This prevents overriding its behavior but also
        // ensures correct behavior when using converters that consume all types.
        converterFactories.add(new BuiltInConverters());
        converterFactories.addAll(this.converterFactories);
        converterFactories.addAll(platform.defaultConverterFactories());
        
        //然后返回了一个Retrofit对象。
        return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
    

    build()方法里可以看出,其实就是创建了一个OkHttpClient的对象,然后进行一系列的配置然后返回一个Retrofit的对象,这里是默认创建一个Okhttp的对象的,这也就代表你也可以外部创建一个Okhttp的对象然后进行传入,比如:

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://wanandroid.com/wxarticle/chapters/json/")
        .addConverterFactory(GsonConverterFactory.create())
        //这里传入外部创建的okhttp对象
        .client(new OkHttpClient())
        .build();
    

    创建网络接口的实例

     //用Retrofit创建接口实例对象
    ApiService apiService = retrofit.create(ApiService.class);
    
    //create()源码
    public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];
    
              @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
              }
            });
    }
    
    ServiceMethod<?> loadServiceMethod(Method method) {
        ServiceMethod<?> result = serviceMethodCache.get(method);
        
        //这里用到了单例模式
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = ServiceMethod.parseAnnotations(this, method);
            serviceMethodCache.put(method, result);
          }
        }
        return result;
    }
    

    然后经过Retrofit的create创建源码,这是一个非常重要的方法,它是会返回一个泛型T,这里运用了Java的动态代理,也就是Proxy.newProxyInstance()这里调用,然后调用了InvocationHandler()invoke()方法,这里Invoke()方法回向江method转换成ServiceMethod对象,然后传入到构造方法中,最后返回一个Call对象,这里面也用到了双重检查的单例模式,这就代表ServiceMethod只会被创建一次,然后我们重点来看看ServiceMethod是什么样的。
    这里需要注意的是Retrofit2.5之前是通过构建者模式进行创建ServiceMethod的,2.5是使用ServiceMethod.parseAnnotations()来进行创建.

    abstract class ServiceMethod<T> {
      static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    
        Type returnType = method.getGenericReturnType();
        if (Utils.hasUnresolvableType(returnType)) {
          throw methodError(method,
              "Method return type must not include a type variable or wildcard: %s", returnType);
        }
        if (returnType == void.class) {
          throw methodError(method, "Service methods cannot return void.");
        }
    
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
      }
    
      abstract T invoke(Object[] args);
    }
    

    这里你会发现它是一个抽象类,这就需要找它的子类的,它的子类是HttpServiceMethod,如下:

    private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
      CallAdapter<ResponseT, ReturnT> callAdapter,
      Converter<ResponseBody, ResponseT> responseConverter) {
    this.requestFactory = requestFactory;
    this.callFactory = callFactory;
    this.callAdapter = callAdapter;
    this.responseConverter = responseConverter;
    }
    
    @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
    }
    

    看到这里,其实也差不多明白了,这里创建了一个HttpServiceMethod对象,然后在Retrofit的create()的方法中调用了invoke()方法,返回了一个Call对象,就是我最初刚刚开始说的那个返回,主要是通过callAdapter.adapt()返回,allAdapter.adapt()方法就是将OkHttpCall对象转换成其他平台能用的Call对象,比如:RxJava。这里返回的是OkHttpCall的对象,该类是Retrofit中定义的,是对Okhttp中的Call对象的封装。

    Retrofit的异步操作

    @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) {
          // 回调后 利用 MainThreadExecutor 中的 Handler 切换到主线程中去。
          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);
            }
          });
        }
      });
    }
    

    其实在异步操作这里主要是看它是怎么切换线程的,这里面有一个delegate,就是从这里进行网络请求的,它是一个OkHttpCall,具体的Call请求是交给okhttp来完成的,完成后通过主线程的Handler来切换到主线程中去,具体的网络请求,会写一篇okhttp的源码解析来继续。

    参考

    相关文章

      网友评论

        本文标题:Android日记之Retrofit源码解析

        本文链接:https://www.haomeiwen.com/subject/naunmctx.html