2016-05-08 09:35:58

这篇文章解析一下Retrofit的调用流程

1. 先看一下我们是如何使用Retrofit的,代码如下:

 1 public interface WeatherDataService {
 2     @GET("/wtr-v2/temp/realtime")
 3     Call<MiWeatherData> getMiWeather(@Query("cityId") String cityId);
 4 
 5     @GET("/wtr-v2/temp/realtime")
 6     Observable<MiWeatherData> getMiWeatherObservable(@Query("cityId") String cityId);
 7 
 8     @GET("/wtr-v2/temp/realtime")
 9     MiWeatherData getMiWeatherCustomCallAdapter(@Query("cityId") String cityId);
10 }

这是获取天气信息的三个请求方法,区别在于返回值不同。下面代码展示了getWeather()是如何调用的,返回值类型时标准的Call<T>:

 1     private void getWeather() {
 2         retrofit = new Retrofit.Builder()
 3                 .baseUrl("http://weatherapi.market.xiaomi.com")
 4                 .addConverterFactory(GsonConverterFactory.create(gson))
 5                 .build();  (1)
 6         service = retrofit.create(WeatherDataService.class);  (2)
 7         Call<MiWeatherData> result = service.getMiWeather("101010100");  (3)
 8 
 9         try {
10             Response<MiWeatherData> r = result.execute();  (4)
11             MiWeatherData data = r.body();  (5)
12             Log.e("David", "ResponseBody data = " + data);
13             if (data != null) {
14                 Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.SD);
15                 Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.cityid);
16                 Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.WS);
17             }
18         } catch (IOException e) {
19             e.printStackTrace();
20         }
21     }

(1)构建Retrofit对象,因为返回值是json串,所以用GsonConverter,使用默认的CallAdapter,也就是说返回值是Call<T>;

(2)使用动态代理创建我们自己定义的WeatherDataService接口实例;

(3)调用接口中真正获取天气信息的方法,返回值是Call<T>;

(4)调用Call<T>的execute()方法,真正执行网络请求,前面的UML途中提到过,还有一个enqueue()方法,两方法的区别是:execute()是同步且在主线程,enqueue()是异步且在工作线程,这里的工作线程不是我们设置的callbackExecutor,而是有okhttp3来控制的;

(5)由于getWeather()方法返回的是Response<T>,body()方法取到真正的MiWeatherData对象,Gson已经将json转换为Object;

 

2. 调用流程解析

其实整个调用流程最关键的就是上面提到的5个点,我们顺着这5个点来探究一下Retrofit是怎么调用的。

第一步就不用多说了,构建Retrofit对象,参数的作用上一篇文章已经做过分析了。

第二、三步很重要,我们看一下create()方法:

从(1)可以发现,确实是使用了动态代理,返回值就是我们自定义的接口实例对象T。由于T的所有方法都是抽象方法,当调用T的方法时,会被InvocationHandler拦截,真正的调用会转到InvocationHandler的invoke()方法中,其中method参数就是我们自己的抽象方法。

(2)处代码基于我们自己的method构造了一个ServiceMethod,构建过程中对方法中的各种注解做了解析,作用前面讲过了。又创建了一个OkHttpCall对象,这个对象将会在被adapt之后返回给客户端,类型取决于客户端的方法返回类型和设置的CallAdapter。这里的代码其实不是很好,耦合性太高,其实本意只是将OkHttpCall转换成客户端需要的返回值,那么CallAdapter对象是否有必要放在ServiceMethod,可以再仔细斟酌一下。

第四步execute网络请求,看一下源码:

1处代码创建一个真正的网络请求okhttp3.Call对象,源码如下:

首先调用了ServiceMethod的toRequest方法得到Request,里面包含了请求类型、请求参数等。然后调用了ServiceMethod的callFactory的newCall方法,这里的CallFactory是Retrofit.Builder的callFactory()设置的参数,默认使用OkHttpClient,我们也可以定义自己的网络请求类,只需要实现okhttp3的Call接口即可。因此默认使用的最终的网络请求类其实是okhttp3.RealCall。

2处代码执行真正的网络请求,绕了这么一大圈,终于进入正题了,同时对返回值做了解析。

其中调用了ServiceMethod的toResponse()方法,源码:

 

这里真正使用了我们设置的Converter,返回客户端需要类型的返回值。

 

3. 最终的流程图

作者在Retrofit的构建中使用了不少的设计模式,达到了耦合性低、扩展性强、灵活性高的目的。

 

 posted on 2016-05-08 10:30  wlrhnh  阅读(1895)  评论(1编辑  收藏  举报