2016-05-08 09:35:58
这篇文章解析一下Retrofit的调用流程
1. 先看一下我们是如何使用Retrofit的,代码如下:
public interface WeatherDataService {
@GET("/wtr-v2/temp/realtime")
Call<MiWeatherData> getMiWeather(@Query("cityId") String cityId); @GET("/wtr-v2/temp/realtime")
Observable<MiWeatherData> getMiWeatherObservable(@Query("cityId") String cityId); @GET("/wtr-v2/temp/realtime")
MiWeatherData getMiWeatherCustomCallAdapter(@Query("cityId") String cityId);
}
这是获取天气信息的三个请求方法,区别在于返回值不同。下面代码展示了getWeather()是如何调用的,返回值类型时标准的Call<T>:
private void getWeather() {
retrofit = new Retrofit.Builder()
.baseUrl("http://weatherapi.market.xiaomi.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.build(); (1)
service = retrofit.create(WeatherDataService.class); (2)
Call<MiWeatherData> result = service.getMiWeather("101010100"); (3)
try {
Response<MiWeatherData> r = result.execute(); (4)
MiWeatherData data = r.body(); (5)
Log.e("David", "ResponseBody data = " + data);
if (data != null) {
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.SD);
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.cityid);
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.WS);
}
} catch (IOException e) {
e.printStackTrace();
}
}
(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的构建中使用了不少的设计模式,达到了耦合性低、扩展性强、灵活性高的目的。