简单研究下Retrofit

2015-09-24 15:36:26

第一部分:

1. 什么是Retrofit?

(点击图片有惊喜)

以上是来自官网的解释,言简意赅,咳咳,我就不翻译了~

2. 如何使用Retrofit?

2.1 具体的请大家参考官网的配置或者下载jar包~

    不过当前好像v2.0.0.1-Beta jar,改动很大(删除了RestAdapter,真不知道他们怎么考虑向后兼容的问题),而且还是beta版,所以我的研究都是基于1.9.0,这个版本实际使用的也比较多。需要的同学可自行下载相关的jar包和源码包,列表如下:

jar包下载

涉及到的jar包比较多,比如okhttp、rxjava、rxandroid等,由于Retrofit支持RxJava和RxAndroid,而且用到了OkHttp,所以一并打包。至于RxJava的功能和使用,有时间再研究吧,挺好的想法。

2.2 如何使用Retrofit?

第一步:创建一个interface,Retrofit将HTTP请求转换成一个interface

public interface ApiManagerService {
    @GET("/weather")
    Observable<WeatherData> getWeather(@Query("q") String place, @Query("units") String units);

    @GET("/weather")
    WeatherData getWeatherBody(@Query("q") String place, @Query("units") String units);

    @GET("/weather")
    void getWeatherCallback(@Query("q") String place, @Query("units") String units, Callback<WeatherData> callback);

    @FormUrlEncoded
    @POST("/weather")
    WeatherData getWeatherField(@Field("name") String name, @Field("id") String id);
}

第二步:创建一个ApiManagerService的Proxy对象,同时设置请求的url前部,之所以叫“前部”,是因为这里设置的“http://api.openweathermap.org/data/2.5”+“/weather”才能形成一个完整的请求URL。此处的URL是一个国外的提供天气的URL。

1     RestAdapter restAdapter = new RestAdapter.Builder()
2             .setEndpoint("http://api.openweathermap.org/data/2.5")
3             .setClient(new MyClient(new OkClient()))
4             .build();
5 
6     final ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);

第三步:调用。注意此调用是一个同步调用,在当前线程,如果是Android,那就是在UI线程,至于原因,我们后面解析。

1 WeatherData data = apiManager.getWeatherBody("Budapest,hu", "metric");

WeatherData.java是一个用来解析json的Object,部分代码如下:

1 public class WeatherData {
2     public String base;
3     public long id;
4     public long dt;
5     public String name;
6     public int cod;
7 }

很简单吧,我们很轻松的搞定了一个GET网络请求,并且了返回了一个我们自己想要的Object,而不是一大串的Json~

2.3 Retrofit封装了多种网络请求和请求形式,比如:GETPOSTPUTDELETE,和各种丰富的参数形式,如:@Path、@Query、@QueryMap、@Field等。这些都比较简单,大家参考一下官网的介绍就好了。

第二部分:

大家是不是觉得特别神奇,反正我刚接触到这玩意的时候觉得挺神奇的~下面我们就来一点一点的扒开她的神秘面纱~

1. 先从RestAdapter入手,大家可以发现RestAdapter是个关键。首先看看RestAdapter是怎么创建的,代码如下:

1 RestAdapter restAdapter = new RestAdapter.Builder()
2     .setEndpoint("http://api.openweathermap.org/data/2.5")
3     .setClient(new MyClient(new OkClient()))
4     .build();

使用了Builder,可见创建RestAdapter对象需要的参数都是可选的,事实证明确实是这样,看源码:

 1 private RestAdapter(Endpoint server, Provider clientProvider, Executor httpExecutor, Executor callbackExecutor, RequestInterceptor requestInterceptor, Converter converter, Profiler profiler, ErrorHandler errorHandler, RestAdapter.Log log, RestAdapter.LogLevel logLevel) {
 2         this.serviceMethodInfoCache = new LinkedHashMap();
 3         this.server = server;
 4         this.clientProvider = clientProvider;
 5         this.httpExecutor = httpExecutor;
 6         this.callbackExecutor = callbackExecutor;
 7         this.requestInterceptor = requestInterceptor;
 8         this.converter = converter;
 9         this.profiler = profiler;
10         this.errorHandler = errorHandler;
11         this.log = log;
12         this.logLevel = logLevel;
13     }

这是RestAdapter的私有构造器~再看看RestAdapter.Builder

 1 public RestAdapter build() {
 2             if(this.endpoint == null) {
 3                 throw new IllegalArgumentException("Endpoint may not be null.");
 4             } else {
 5                 this.ensureSaneDefaults();
 6                 return new RestAdapter(this.endpoint, this.clientProvider, this.httpExecutor, this.callbackExecutor, this.requestInterceptor, this.converter, this.profiler, this.errorHandler, this.log, this.logLevel, null);
 7             }
 8         }
 9 
10         private void ensureSaneDefaults() {
11             if(this.converter == null) {
12                 this.converter = Platform.get().defaultConverter(); // 1
13             }
14 
15             if(this.clientProvider == null) {
16                 this.clientProvider = Platform.get().defaultClient(); // 2
17             }
18 
19             if(this.httpExecutor == null) {
20                 this.httpExecutor = Platform.get().defaultHttpExecutor(); // 3
21             }
22 
23             if(this.callbackExecutor == null) {
24                 this.callbackExecutor = Platform.get().defaultCallbackExecutor(); // 4
25             }
26 
27             if(this.errorHandler == null) {
28                 this.errorHandler = ErrorHandler.DEFAULT; // 5
29             }
30 
31             if(this.log == null) {
32                 this.log = Platform.get().defaultLog(); // 6
33             }
34 
35             if(this.requestInterceptor == null) {
36                 this.requestInterceptor = RequestInterceptor.NONE; // 7
37             }
38 
39         }

我只贴出来了关键部分的代码,至于那些set***()就没必要了吧~看红色部分代码,ensureSaneDefaults()方法确保每一个RestAdapter需要的参数都是初始化了的,所以创建RestAdapter的时候你可以不用set任何参数。下面我们逐个看看初始化的参数。

首先说明一下,Retrofit在初始化这些参数的时候是区别对待Android和Base(Java)的,不同的platform有不同的实现。

//1 初始化converter,这个就是帮你解析json的转换器,在Android和Base都使用的是自己定义的GsonConverter,其中使用了Google的Gson。

//2 初始化clientProvider,就是执行http请求的HttpClient,Android平台如下

 1 Provider defaultClient() {
 2     final Object client;
 3     if(Platform.hasOkHttpOnClasspath()) {
 4         client = Platform.OkClientInstantiator.instantiate();
 5     } else if(VERSION.SDK_INT < 9) {
 6         client = new AndroidApacheClient();
 7     } else {
 8         client = new UrlConnectionClient();
 9     }
10 
11     return new Provider() {
12         public Client get() {
13             return (Client)client;
14         }
15     };
16 }

在这里考虑到了Android平台API Level 9前后的区别,赞一个~

Base平台如下:

 1 Provider defaultClient() {
 2     final Object client;
 3     if(Platform.hasOkHttpOnClasspath()) {
 4         client = Platform.OkClientInstantiator.instantiate();
 5     } else {
 6         client = new UrlConnectionClient();
 7     }
 8 
 9     return new Provider() {
10         public Client get() {
11             return (Client)client;
12         }
13     };
14 }

所以推荐大家使用OKHttpClient

//3 初始化httpExecutor,其实Retrofit在执行请求时,用的还是Executor,所以这里需要初始化。这个参数Android和Base平台是一样的,代码如下:

 1 Executor defaultHttpExecutor() {
 2     return Executors.newCachedThreadPool(new ThreadFactory() {
 3         public Thread newThread(final Runnable r) {
 4             return new Thread(new Runnable() {
 5                 public void run() {
 6                     Process.setThreadPriority(10);
 7                     r.run();
 8                 }
 9             }, "Retrofit-Idle");
10         }
11     });
12 }

其他的几个参数就不一一分析了,大家自己去看吧~

 2. 创建真正给我们使用的Interface对象,比如:

1 final ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);
2 WeatherData data = apiManager.getWeatherBody("Budapest,hu", "metric");

有了ApiManagerService对象,我们就能调用它的方法了。现在我们顺着RestAdapter.create方法去看看,这个对象是怎么创建的,以及我们调用方法时是如何执行的~

1 public <T> T create(Class<T> service) {
2     Utils.validateServiceClass(service);
3     return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
new RestAdapter.RestHandler(this.getMethodInfoCache(service))); 4 }

看代码,使用动态代理的方式返回了一个Proxy对象,不知道动态代理的可自行百度~动态代理最终调用方法是在InvocationHandler中,我们来看RestAdapter.RestHandler~

到目前为止,我们知道了Retrofit是通过动态代理的方式来调用我们接口中的方法~

3. RestAdapter.RestHandler继承自InvocationHandler,重点看它的invoke()。invoke()将会是真正调用方法的地方,Retrofit在这个方法中,做了大量的判断和解析,当然,这些判断和解析是基于RestMethodInfo,它为每一个method创建了一个RestMethodInfo,我们先看看RestMethodInfo对象是怎么创建的,里面有哪些信息。

1 RestMethodInfo(Method method) {
2     this.requestType = RestMethodInfo.RequestType.SIMPLE;
3     this.method = method;
4     this.responseType = this.parseResponseType();
5     this.isSynchronous = this.responseType == RestMethodInfo.ResponseType.OBJECT;
6     this.isObservable = this.responseType == RestMethodInfo.ResponseType.OBSERVABLE;
7 }

以上是RestMethodInfo的构造器

requestType:代表的是请求类型,主要是用于解析和判断Annotation和请求类型,比如POST、GET亦或是FormUrlEncoded

method:就是实际要调用的方法

responseType:很重要,这里涉及到Retrofit定义方法的方式,代码如下:

 1 private RestMethodInfo.ResponseType parseResponseType() {
 2         Type returnType = this.method.getGenericReturnType();
 3         Type lastArgType = null;
 4         Class lastArgClass = null;
 5         Type[] parameterTypes = this.method.getGenericParameterTypes();
 6         if(parameterTypes.length > 0) {
 7             Type hasReturnType = parameterTypes[parameterTypes.length - 1];
 8             lastArgType = hasReturnType;
 9             if(hasReturnType instanceof ParameterizedType) {
10                 hasReturnType = ((ParameterizedType)hasReturnType).getRawType();
11             }
12 
13             if(hasReturnType instanceof Class) {
14                 lastArgClass = (Class)hasReturnType;
15             }
16         }
17 
18         boolean hasReturnType1 = returnType != Void.TYPE;
19         boolean hasCallback = lastArgClass != null && Callback.class.isAssignableFrom(lastArgClass);
20         if(hasReturnType1 && hasCallback) {
21             throw this.methodError("Must have return type or Callback as last argument, not both.", new Object[0]);
22         } else if(!hasReturnType1 && !hasCallback) {
23             throw this.methodError("Must have either a return type or Callback as last argument.", new Object[0]);
24         } else if(hasReturnType1) {
25             if(Platform.HAS_RX_JAVA) {
26                 Class rawReturnType = Types.getRawType(returnType);
27                 if(RestMethodInfo.RxSupport.isObservable(rawReturnType)) {
28                     returnType = RestMethodInfo.RxSupport.getObservableType(returnType, rawReturnType);
29                     this.responseObjectType = getParameterUpperBound((ParameterizedType)returnType);
30                     return RestMethodInfo.ResponseType.OBSERVABLE;
31                 }
32             }
33 
34             this.responseObjectType = returnType;
35             return RestMethodInfo.ResponseType.OBJECT;
36         } else {
37             lastArgType = Types.getSupertype(lastArgType, Types.getRawType(lastArgType), Callback.class);
38             if(lastArgType instanceof ParameterizedType) {
39                 this.responseObjectType = getParameterUpperBound((ParameterizedType)lastArgType);
40                 return RestMethodInfo.ResponseType.VOID;
41             } else {
42                 throw this.methodError("Last parameter must be of type Callback<X> or Callback<? super X>.", new Object[0]);
43             }
44         }
45     }

分解如下:

:1. 如果定义的方法有返回值,并且最后一个参数是Callback,那么该方法错误

:2. 如果定义的方法没有返回值,并且最后一个参数不是Callback,那么该犯方法错误

:3. 如果只有返回值,会判断返回值是否是Observable<WeatherData>,如果是,那么responseType是OBSERVABLE,否则是OBJECT

:4. 其他的都是没有返回值,但是有Callback的,responseType是VOID

isSynchronous:(this.responseType == RestMethodInfo.ResponseType.OBJECT),表示该方法是否是同步的,如果是同步的,则在当前线程调用,否则,异步调用。根据responseType的判断,我们发现:只有有返回值且返回值不是Observable类型的方法,是同步调用的。其他的都是异步调用。还记得前面提到过apiManager.getWeatherBody("Budapest,hu", "metric")是同步调用的吗?原因就在这里。

isObservable:只有返回值是Observable的方法才是,这个参数有特殊的用途,所以是一个独立的参数。

4. 真正分析invoke()方法

 1     public Object invoke(Object proxy, Method method, final Object[] args) throws Throwable {
 2         if(method.getDeclaringClass() == Object.class) {
 3             return method.invoke(this, args); //忽略
 4         } else {
 5             final RestMethodInfo methodInfo = RestAdapter.getMethodInfo(this.methodDetailsCache, method);
 6             if(methodInfo.isSynchronous) {
 7                 try {
 8                     return this.invokeRequest(RestAdapter.this.requestInterceptor, methodInfo, args);
 9                 } catch (RetrofitError var7) {
10                 }
11             } else if(RestAdapter.this.httpExecutor != null && RestAdapter.this.callbackExecutor != null) {
12                 if(methodInfo.isObservable) {
13                     if(RestAdapter.this.rxSupport == null) {
14                         if(!Platform.HAS_RX_JAVA) {
15                             throw new IllegalStateException("Observable method found but no RxJava on classpath.");
16                         }
17 
18                         RestAdapter.this.rxSupport = new RxSupport(RestAdapter.this.httpExecutor, RestAdapter.this.errorHandler, RestAdapter.this.requestInterceptor);
19                     }
20 
21                     return RestAdapter.this.rxSupport.createRequestObservable(new RxSupport.Invoker() {
22                         public ResponseWrapper invoke(RequestInterceptor requestInterceptor) {
23                             return (ResponseWrapper)RestHandler.this.invokeRequest(requestInterceptor, methodInfo, args);
24                         }
25                     });
26                 } else {
27                     final RequestInterceptorTape interceptorTape = new RequestInterceptorTape();
28                     RestAdapter.this.requestInterceptor.intercept(interceptorTape);
29                     final Callback callback = (Callback)args[args.length - 1];
30                     RestAdapter.this.httpExecutor.execute(new CallbackRunnable(callback, RestAdapter.this.callbackExecutor, RestAdapter.this.errorHandler) {
31                         public ResponseWrapper obtainResponse() {
32                             return (ResponseWrapper)RestHandler.this.invokeRequest(interceptorTape, methodInfo, args);
33                         }
34                     });
35                     return null;
36                 }
37             } else {
38                 throw new IllegalStateException("Asynchronous invocation requires calling setExecutors.");
39             }
40         }
41     }

根据得到的RestMethodInfo:

1. 如果methodInfo.isSynchronous为true,那么invokeRequest,这个方法中调用this.clientProvider.get().execute(request)在当前线程

2. 如果需要异步调用,那么判断是不是Observable,

如果是:

    判断平台是否支持RxJava环境,如果不支持,直接异常,如果支持,利用RxJava,由httpExecutor来执行。

如果不是:

    那就是说,该方法有Callback,同样由httpExecutor执行,当然了,结果在Callback中返回,Callback方法在callbackExecutor中执行。如果是Android,那么Callback就是在UI线程。如果是Base,那个线程调用,在哪个线程中执行。

原文地址:https://www.cnblogs.com/wlrhnh/p/4835596.html