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包比较多,比如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封装了多种网络请求和请求形式,比如:GET
, POST
, PUT
, DELETE,和各种丰富的参数形式,如:@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,那个线程调用,在哪个线程中执行。