三方框架原理

Retrofit初探和源码解析

2017-05-09  本文已影响26人  CHSmile

前言

在使用了一段时间的Retrofit之后,今天终于在这里讲解到了网络的部分。目前开源的HTTP 框架有很多,Volley,Android Async Http,以及OkHttp +Retrofit等。而我在自己的使用中选择了Retrofit,这里就从基础到原理,再到实例的方式,讲解我对Retrofit做出的一些封装和使用。来让你进一步的了解和掌握Retrofit的使用。

基础

Retrofit一个基于OkHttp的RESTFUL API请求工具。它是 Square 推出的 HTTP 框架,主要用于 Android 和 Java。Retrofit 将网络请求变成方法的调用,使用起来非常简洁方便。

A type-safe HTTP client for Android and Java

如果你还对Retrofit不了解,那么我建议你去官方文档了解一下。
Retrofit使用大体分为三个步骤
(1)Retrofit将HTTP API 转化成了Java接口的形式,所以首先我们会提供一个接口类GitHubService 。

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

(2)Retrofit类可以针对之前定义的GitHubService 接口生成一个具体实现。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);

(3)然后就可以对GitHubService 的方法进行同步或者异步的调用来进行网络的访问,也就是说可以通过call对象获得数据:(可以使用enqueue 或者 execute来执行发起请求,enqueue是是异步执行,而 execute是同步执行。)

 Call<List<Repo>> repos = service.listRepos("octocat"); 

通过上面三个步骤,我们会发现Retrofit给人眼前一亮的当然是它的注解调用和优雅的API转化为方法。每一个方法都会对应着一个Http的注解,总共有GET, POST, PUT, DELETE,HEAD五个内嵌的注解。我们也会在注解上指定相应的相对地址信息。比如上方的@GET("users/{user}/repos")

这里本来想将官网所有内容翻译一遍的,返现很多词不达意 。然后今天又凑巧看到了郭神公众号推荐的一篇文章 Android网络请求库 - Say hello to retrofit.对官网对的内容讲解得非常的详细易懂,继续阅读下面章节之前,一定要去看看这篇文章。
于是我们完整的Retrofit使用流程:

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
//.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();

GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {

    }
    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {

    }
 });

Retrofit原理解析

在进一步了解和使用Retrofit之前,不妨先来了解Retrofit的原理,看看Retrofit的源码是了解原理的一个有效途径。

(1) 源码结构
Retrofit包含一个http包,里面全部是定义HTTP请求的Java注解,比如GET、POST、PUT、DELETE、Headers、Path、Query等等。
余下的retrofit包中几个类和接口就是全部retrofit的代码了,代码很少因为retrofit把网络请求这部分功能全部交给了OkHttp了。




(2) 整体流程
继续回到官网的例子。

首先关注的是我们通过new Retrofit.Builder()...build()进行Retrofit的构建,可以了解的是这里使用的是 Builder 模式。

在Android源码中,经常用到Builder模式的可能就是AlerDialog 了。Builder模式用于将一个复杂的对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。这里Retrofit使用Builder模式支持了支持不同的转换(就是将HTTP返回的数据解析成Java对象,主要有Xml、Gson等)和返回(主要作用就是将Call对象转换成另一个对象,比如RxJava)。这里也就真正的达到了构建复杂对象和它的部件进行解耦。
这里通过build方法来了解Retrofit创建,需要6个参数。如下方代码注解:

public Retrofit build() {
      //1 baseUrl   基地址
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //2 callFactory  默认创建一个 OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        //3 callbackExecutor  Android 中返回的是 MainThreadExecutor
        callbackExecutor = platform.defaultCallbackExecutor();
      }

     //4 adapterFactories(比如RxJavaCallAdapterFactory 用于将Call返回支持Rxjava)  把Call对象转换成其它类型
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      //5  converterFactories(例如GsonConverterFactory 用于Gson转换)  请求网络得到的response的转换器的集合 默认会加入 BuiltInConverters ,
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      //6 private boolean validateEagerly;  validateEagerly 是否需要立即解析接口中的方法

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }

所以我们会看到我们通过Builder模式创建Retrofit访问对象都必须指定基地址url。如果还需要支持Gson转换,我们就需要添加.addConverterFactory(GsonConverterFactory.create()),如果需要支持Rxjava,那么还需要添加 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())

接着我们通过GitHubService service = retrofit.create(GitHubService.class); create方法创建网络请求接口类GitHubService 的实例。我们正是使用该对象的listRepos方法完成了Call<List<Repo>> repos = service.listRepos("octocat"); 获取到了数据。下面看看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();

          @Override public Object invoke(Object proxy, Method method, 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);
            }
            //为了兼容 Java8 平台,Android 中不会执行
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

create方法接受一个 Class 对象,也就是我们编写的接口,里面含有通过注解标识的请求网络的方法。注意 return语句部分,这里调用了 Proxy.newProxyInstance方法,这个很重要,因为用了动态代理模式。关于动态代理模式,可以参考这篇文章:公共技术点之 Java 动态代理。简单的描述就是,Proxy.newProxyInstance根据传进来的 Class 对象生成了一个实例 A,也就是代理类。每当这个代理类 A 执行某个方法时,总是会调用 InvocationHandler(Proxy.newProxyInstance中的第三个参数) 的invoke方法,在这个方法中可以执行一些操作(这里是解析方法的注解参数等),通过这个方法真正的执行我们编写的接口中的网络请求。

也就是概括一句话:通过动态代理的方式把 Java 接口中的解析为响应的网络请求,然后交给 OkHttp 去执行。并且可以适配不同的 CallAdapter
,可以方便与 RxJava 结合使用。

更多源码细节,参考这篇文章。Android Retrofit源码解析

上一篇下一篇

猜你喜欢

热点阅读