Retrofit源码分析

栏目: IOS · Android · 发布时间: 5年前

内容简介:在学习了首先我们聊一下对于一个优秀的libary,应该怎样一步一步地分析它。在上面的视频中,介绍了一个很好的方法。分为三个阶段:通过了解、深入、思考,将整个框架一层一层地剖析出来,由浅入深,最后从全局再看这个框架,或许我们会不自禁的赞叹代码的美妙。

在学习了 Retrofit分析-漂亮的解耦套路(视频版) 后,自己又仔细的钻研了一下Retrofit的源码,也大致清楚了Retrofit进行网络请求的步骤。好记性不如烂笔头,以文章的形式将对于Retrofit的思考记录下来,也加深理解。(如有错误,请不吝赐教)

分析源码的一般姿势

首先我们聊一下对于一个优秀的libary,应该怎样一步一步地分析它。在上面的视频中,介绍了一个很好的方法。分为三个阶段:

  • what: 这个框架是用来干什么的,暴露给用户的API都是用来干嘛的。
  • how: 这个API内部是怎样实现的,整个框架正常调用时内部是一个怎样的流程。
  • why: 为什么要这样实现,有什么好处,可不可以有其他的实现,与原来的实现相比怎么样。

通过了解、深入、思考,将整个框架一层一层地剖析出来,由浅入深,最后从全局再看这个框架,或许我们会不自禁的赞叹代码的美妙。

Retrofit使用(what)

详细的了解Retrofit使用及API可以到Retrofit的Github。

简单使用

首先,我们需要创建一个请求接口,内部是一个请求方法,通过注解的方式定义请求类型及url

public interface IHttpRequestTest {
    @GET("api/data/福利/{number}/{page}")
    Call<BaseModel<ArrayList<Benefit>>> getBenefits(@Path("number") int number, @Path("page") int page);
}
复制代码

然后我们就可以愉快地使用Retrofit。

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://gank.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
IHttpRequestTest iHttpRequestTest = retrofit.create(IHttpRequestTest.class);
Call<BaseModel<ArrayList<Benefit>>> call = iHttpRequestTest.getBenefits(40, 2);
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
    @Override
    public void onResponse(@NonNull Call<BaseModel<ArrayList<Benefit>>> call, @NonNull Response<BaseModel<ArrayList<Benefit>>> response) {
        if(response.body() != null && response.body().results != null){
            myAdapter.setData(response.body().results);
        }
    }

    @Override
    public void onFailure(@NonNull Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
        Toast.makeText(MainActivity.this, "请求失败:" + t.getMessage(),Toast.LENGTH_SHORT).show();
    }
});
复制代码

一般http的请求步骤

Retrofit源码分析

如上图,对于一般http请求:

  • 生成request请求,包括请求类型,url等等,放入Excutor队列
  • 请求在Excutor中循环进行httpcall请求
  • 等待请求回调

接下来,我们就可以根据这个一般的http请求步骤,通过debug的形式弄清楚Retrofit的内部逻辑。

Retrofit源码解析

探索Retrofit对象初始化时参数的真正含义

首先第一步,就是生产Retrofit对象,并传入基本的参数。

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://gank.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
复制代码

进入Retrofit类的源码,可以看到build方法

public Retrofit build() {
    if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
    }
    
    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }
    //如果callbackExcutor为空,创建默认的callbackEcxutor
    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
    }

    // Make a defensive copy of the adapters and add the default Call adapter.
    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    //添加默认的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,将使用默认的converterFactories
    converterFactories.addAll(platform.defaultConverterFactories());
    //返回Retrofit对象,包括在Builder中添加的自定义参数。
    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
        unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
复制代码

可以看到,生成的retrofit对象有五个参数必须要存在。

  • baseUrl 就不用多说了,是必须的。
  • callFactory 使用的是OkHttp3中的 OkHttpClient
  • callbackExcutorcallAdapterFactory 中的 callAdapter 都对应一般请求步骤中的 Excutor ,只不过 callbackExcutor 用于在请求内部回调中切换线程,回调的方法存在哪个线程中取决于 callbackExcutor 在哪个线程。比如请求要在子线程中,回调的方法在主线程中。
  • callAdapter 是真正的请求对象, callbackExcutor 相当于在 callAdapter 中切换线程。
  • converterFactory 是用来解析返回的json数据的。当然这些具体的解释在下面的分析中都会看到。

有源码可看出,默认的 callbackExcutorcallAdapterFactoryconverterFactory 添加都与 platform 对象有关。这是一个 Platform 类,进入研究一下。

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();
  }
  
  @Nullable Executor defaultCallbackExecutor() {return null;}

  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {...}

  List<? extends Converter.Factory> defaultConverterFactories() {...}

  @IgnoreJRERequirement // Only classloaded and used on Java 8.
  static class Java8 extends Platform {...}

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }

    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}
复制代码

内容有点多,这里我只提取了对现在有用的。整体来看, Platform 内部有两个子类继承了该类 Android与 Java 8 。还有一个get方法,获取Platform静态实例,静态实例调用findPlatform()方法。这个方法是根据程序所执行的环境决定是返回一个 Android 实例还是 Java8 实例或者 Platform 实例。这里我们的环境是 Android ,所以具体看 Android 类中的方法。

  • defaultCallbackExecutor()方法,返回了 MainThreadExecutor 类实例。此类在Android类内部,可以清晰的看出其中的handler静态变量是用的主线程的looper。也就是说,默认的 callbackExcutor 是运行在主线程的。
  • defaultCallAdapterFactories()方法,参数是上面得到的 callbackExcutor 。方法内部创建了 ExecutorCallAdapterFactory 类实例,并返回该实例的List。
  • defaultConverterFactories()方法,返回了 OptionalConverterFactory 实例,此类中的转换 converter() 方法只检查了参数是否为空就将其返回了,说明默认的回调数据是不进行任何转换的。

至此,三个默认参数已确定。

获得自定义接口对象

IHttpRequestTest iHttpRequestTest = retrofit.create(IHttpRequestTest.class); 这是接下来的执行步骤,自定义接口对象由retrofit类中的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);
          }
        });
  }
复制代码

该方法返回的是通过反射获得自定义接口的代理类,并在类中重写了invoke方法。这表明当该类中的方法被执行时,就会拦截此方法。

拦截并解析方法。

Call<BaseModel<ArrayList<Benefit>>> call = iHttpRequestTest.getBenefits(40, 2); 由上一步骤可知,当执行代理类中的方法时,会被拦截。并最终执行 loadServiceMethod(method).invoke(args != null ? args : emptyArgs); 方法并返回。先看一下 loadServiceMethod(method) 方法。

ServiceMethod<?> loadServiceMethod(Method method) {
    //serviceMethodCache,如果执行过此方法,就会有缓存存在这里,直接取出即可
    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;
  }
复制代码

嗯...,除了前面与缓存有关的东西,又跑到了 ServiceMethod 类中的 parseAnnotations(this, method) 方法里。

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);
}
复制代码

这是一个抽象类,第一句 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); ,是解析方法构建request参数的。RequestFactory类中内容比较多,简单讲一下就是通过获得方法注解、返回类型、方法参数,分别进行解析。

最后它又跑到 HttpServiceMethod 类中了。此类继承了 ServiceMethod 类。

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
  }
  
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    
    return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  }

  private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    
    return retrofit.responseBodyConverter(responseType, annotations);
  }
复制代码

简化了异常检测类代码,可以看到最后返回的是 HttpServiceMethod 类的实例对象,并将retrofit中的一些默认参数传了进去。

解析完了 loadServiceMethod(method) ,接下来就是执行invoke方法了。由于 loadServiceMethod(method) 返回的是 HttpServiceMethod 类的实例对象,所以执行的就是 HttpServiceMethod 类中的invoke方法。

@Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }
复制代码

此方法很简单,调用了callAdapter中的adapt方法,参数是一个OkHttpCall,字面意思就是将 OkHttpCall 适配为其他类。那么这个类是什么什么呢。应该是我们需要返回的 Call<BaseModel<ArrayList<Benefit>>> 类。那么怎么适配的呢。上面我们已经说到,retrofi中的默认参数 callAdapterFactoriesExecutorCallAdapterFactory 类,而 callAdapterFactories 中的 callAdapter 是通过 callAdapterFactories.get() 获得的,那么就要去这里面找了。

@Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
复制代码

返回的 CallAdapter 对象就是我们需要的。其中重写了adapt方法,也是我们要找的。它又返回了 ExecutorCallbackCall 对象,第一个参数就是默认运行在主线程中的 callbackExecutor ,第二个参数则是调用时传进来的 OkHttpCall 对象。所以说我们需要返回的 Call<BaseModel<ArrayList<Benefit>>> 对象就是 ExecutorCallbackCall 对象。

依靠OkHttp3进行网络请求,转换回调函数线程到主线程。

call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {...}); ,终于到最后一步了,拿着上一步返回的 Call<BaseModel<ArrayList<Benefit>>> 对象进行异步请求。调用了enqueue方法,也就是 ExecutorCallbackCall 中的enqueue方法。

ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    @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) {
          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);
            }
          });
        }
      });
    }
复制代码

构造方法给了出来,变量名有些转换。 callbackExecutor 依然是在主线程中的那个 callbackExecutordelegate 是上一步传进来的 OkHttpCall 对象。而enqueue的参数callback则是我们自己传入的callback。

方法中首先是 delegate 也就是OkHttp3进行的异步请求,在回调的函数中,通过 callbackExecutor 使线程切换为主线程,再调用我们自己的callback中对应的函数,使我们可以再回调中进行操作,并且是在主线程中。

OkHttpCall 这个类就不在多讲了,主要作用是retrofit通过OkHttp3进行请求的一个转换。

结语

第一次分析源码,虽然有视频的帮助,但许多类之间跳来跳去的让人眼花缭乱,很艰难地顺了下来。有了这样一个大概的了解,接下来就要分析其设计模式,欣赏其漂亮的解耦套路。当然,如果你已经有了上面的了解,接下来看 Retrofit分析-经典 设计模式 案例 就会简单明了。


以上所述就是小编给大家介绍的《Retrofit源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

快速傅里叶变换

快速傅里叶变换

K. R. Rao、D. N. Kim、J. J. Hwang / 万帅、杨付正 / 机械工业出版社 / 2013-3 / 98.00元

《国际信息工程先进技术译丛·快速傅里叶变换:算法与应用》深入浅出地阐述了快速傅里叶变换(FFT)的原理,系统地总结了各类FFT算法,并广泛精辟地介绍了FFT在视频和音频信号处理中的各种应用。《国际信息工程先进技术译丛·快速傅里叶变换:算法与应用》在阐述了离散傅里叶变换(DFT)的原理和性质之后,详细讨论了时域抽取(DIT)和频域抽取(DIF)的各类快速算法。论述了近似计算DFT的整数FFT、二维及......一起来看看 《快速傅里叶变换》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具