现在Retrofit2.0的使用已经非常普遍了,我们先来了解连个问题。
1、什么是Retrofit?
Retrofit是针对Android和Java的,基于okHttp的,轻量级、安全并使用注解的方式的网络请求框架。
2、它有哪些优势
首先,Retrofit使用注解方式,大大简化了我们的URL拼写形式,而且注解含义一目了然,简单易懂;
其次,Retrofit使用简单,结构层次分明,每一步都能清晰的表达出之所以要使用的寓意;
再者,Retrofit支持同步和异步执行,使得请求变得异常简单,只要调用enqueue/execute即可完成;
最后,Retrofit更大自由度的支持我们自定义的业务逻辑,如自定义Converters。
好,知道了Retrofit是什么,有了哪些优势,现在我们来学习下怎么使用。
在学习Retrofit之前,最好先了解下OkHttpClient的使用OkHttp完全解析,因为Retrofit说到底底层还是通过OkHttp来实现的。
一、Retrofit的使用
1、在使用之前说先gradle中添加依赖:
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0' compile files('libs/fastjson.jar')
这里我们使用的是fastjson来解析,同时也支持其他工具来解析,然后导入fastjson.jar包。
2、定义一个接口,用来存放用语网络请求的方法:
public interface HttpApi {
@POST("/DeviceInfo-queryallinfo.php")
Call<BaseArrayResponse<EquipModel>> getEquipInfo(@Body BaseRequest request);
}
@GET和@POST是最常用的注解,分别用来获取和发送网络请求。
3、创建Retrofit对象
public class HttpApiClient {
private static final String BASE_URL = "http://lbsdevicesys.duapp.com";
private static OkHttpClient sOkHttpClient;
private HttpApi mHttpApi;
public HttpApiClient() {
sOkHttpClient = new OkHttpClient();
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
sOkHttpClient.setCookieHandler(cookieManager);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(sOkHttpClient)
.addConverterFactory(new FastjsonConvertFactory<>())
.build();
mHttpApi = retrofit.create(HttpApi.class);
}
private static class HttpApiClientHolder{
private static final HttpApiClient INSTANCE = new HttpApiClient();
}
public static HttpApiClient getInstance() {
return HttpApiClientHolder.INSTANCE;
}
public void getEquipInfo() {
if(mHttpApi != null) {
BaseRequest request = new BaseRequest();
mHttpApi.getEquipInfo(request).enqueue(new retrofit.Callback<BaseArrayResponse<EquipModel>>() {
@Override
public void onResponse(Response<BaseArrayResponse<EquipModel>> response, Retrofit retrofit) {
List<EquipModel> list = response.body().getObjList();
Log.e("weilei", list.get(0).getManufacturer());
}
@Override
public void onFailure(Throwable t) {
Log.e("weilei", "onFailure");
}
});
}
}
}
在这里首先创建一个Retrofit对象,通过Retrofit的构造者分别添加baseUrl、client、conveterFactory,其中baseUrl是必须的,client如果不指定默认就是一个okHttpClient,conveterFactory用于将返回的json字符串转换成我们定义的对象类型,同时将请求参数类型转换成对应的url,这里我们是这么写的,当然方式是多样的:
public class FastjsonConvertFactory<T> extends Converter.Factory{
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
public FastjsonConvertFactory() {}
@Override
public Converter<ResponseBody, T> fromResponseBody(final Type type, Annotation[] annotations) {
return new Converter<ResponseBody, T>() {
@Override
public T convert(ResponseBody value) throws IOException {
return JSON.parseObject(value.string(), type);
}
};
}
@Override
public Converter<T, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
return new Converter<T, RequestBody>() {
@Override
public RequestBody convert(T value) throws IOException {
return RequestBody.create(MEDIA_TYPE, JSON.toJSONString(value).getBytes(UTF_8));
}
};
}
}
最后只用通过调用以下代码就可以发送网络请求了,整个使用过程非常简单、方便、灵活。
HttpApiClient.getInstance().getEquipInfo();
不过我们不能仅限于知道如何使用,还应该将进一步了解它的原理。
二、Retrofit的原理解析
从上面的例子我们可以知道,Retrofit是通过构造者模式构造的,来看一下Retrofit.Builder的build()方法的源码:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
OkHttpClient client = this.client;
if (client == null) {
client = new OkHttpClient();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(client, baseUrl, converterFactories, adapterFactories, callbackExecutor,
validateEagerly);
}
defaultCallAdapterFactory(callbackExecutor)的源码如下:
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapter.FACTORY;
}
DefaultCallAdapter的源码如下:
final class DefaultCallAdapter implements CallAdapter<Call<?>> {
static final Factory FACTORY = new Factory() {
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (Utils.getRawType(returnType) != Call.class) {
return null;
}
Type responseType = Utils.getCallResponseType(returnType);
return new DefaultCallAdapter(responseType);
}
};
private final Type responseType;
DefaultCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return call;
}
}
1、首先判断baseUrl是否为空,为空的话抛出一个异常;
2、然后判断client是否为空,是的话创建一个OkHttpClient对象;
3、在adapterFactories中添加一个CallAdapter.Factory对象,这个CallAdapter.Factory对象是这么来的:
首先我们在构造Retrofit的时候如果传入了一个Executor对象,那么就通过这个Executor对象new一个ExecutorCallAdapterFactory对象;否则就返回一个DefaultCallAdapter.FACTORY。
4、最后一步构建一个List存放Converter.Factory
Retrofit构造完成后结下来会调用它的一个很重要的方法,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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadMethodHandler(method).invoke(args);
}
});
}
在这个方法中是一个典型的应用动态代理的方式生成一个HttpApi的代理对象,当通过代理对象调用方法的时候,会通过调用loadMethodHandler(method).invoke(args)来调用HttpApi中的方法。
下面看一下loadMethodHandler(method).invoke(args)的实现:
MethodHandler<?> loadMethodHandler(Method method) {
MethodHandler<?> handler;
synchronized (methodHandlerCache) {
handler = methodHandlerCache.get(method);
if (handler == null) {
handler = MethodHandler.create(this, method);
methodHandlerCache.put(method, handler);
}
}
return handler;
}
这里通过MethodHandler.create(this,method)创建一个MethodHandler对象,看一下是如何创建的:
static MethodHandler<?> create(Retrofit retrofit, Method method) {
CallAdapter<Object> callAdapter = (CallAdapter<Object>) createCallAdapter(method, retrofit);
Type responseType = callAdapter.responseType();
Converter<ResponseBody, Object> responseConverter =
(Converter<ResponseBody, Object>) createResponseConverter(method, retrofit, responseType);
RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
return new MethodHandler<>(retrofit, requestFactory, callAdapter, responseConverter);
}
首先创建一个CallAdapter,保存CallAdapter对象的type,
创建一个Converter对象,最后new一个MethodHandler对象。
在这里要特别注意创建的CallAdapte和Converter对象,这个在后面都要用到的。
CallAdapter的创建过程如下:
private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw Utils.methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw Utils.methodError(method, "Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw Utils.methodError(e, method, "Unable to create call adapter for %s", returnType);
}
}
然后:
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(". Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
if (skipPast != null) {
builder.append("\nSkipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
}
throw new IllegalArgumentException(builder.toString());
}
可以发现这个CallAdapter对象是通过这条语句来创建的:adapterFactories.get(i).get(returnType, annotations, this);
那么这条语句究竟执行的是什么呢?实际上adapterFactories.get(i)获得的正是我们上面ExecutorCallAdapterFactory或者DefaultCallAdapter.FACTORY 对象,我们就以ExecutorCallAdapterFactory为例来说明,看一下它的get()方法:
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (Utils.getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
在这里会new一个
CallAdapter对象,这个对象在后面将有重要作用,我们先放一放。
再看一下Converter的创建过程:
private static Converter<ResponseBody, ?> createResponseConverter(Method method,
Retrofit retrofit, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw Utils.methodError(e, method, "Unable to create converter for %s", responseType);
}
}
然后:
public <T> Converter<ResponseBody, T> responseConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).fromResponseBody(type, annotations);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
.append(type)
.append(". Tried:");
for (Converter.Factory converterFactory : converterFactories) {
builder.append("\n * ").append(converterFactory.getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
可以看到它现获取method的返回值类型type以及注解,最后调用我们定义的converyerFactory的fromResponseBody方法来生成一个Converter对象,这个对象用语将返回的json字符串转换为对应的type类型。
接着上面的来讲,我们成功创建好了CallAdapter对象后,这个对象是在哪儿被用到了呢?
回到动态代理的位置,打开methodHandler.invoke()方法:
Object invoke(Object... args) {
return callAdapter.adapt(new OkHttpCall<>(retrofit, requestFactory, responseConverter, args));
}
就在这个地方调用这个callAdapter的adapt方法,这个方法是
将OKHttpCall对象转变成我们所需要的Call对象,然后调用enqueue()或者excute()方法来发起网络请求。
这里的adapt()方法在上面创建CallAdapter的时候出现过,源码如下:
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
也就是说最终返回的Call就是此处new的一个ExecutorCallbackCall的对象,当它调用enqueue方法的时候执行如下:
@Override public void enqueue(Callback<T> callback) {
delegate.enqueue(new ExecutorCallback<>(callbackExecutor, callback));
}
也就是还是调用的是okHttpCall的enqueue方法,源码如下:
@Override public void enqueue(final Callback<T> callback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed");
executed = true;
}
com.squareup.okhttp.Call rawCall;
try {
rawCall = createRawCall();
} catch (Throwable t) {
callback.onFailure(t);
return;
}
if (canceled) {
rawCall.cancel();
}
this.rawCall = rawCall;
rawCall.enqueue(new com.squareup.okhttp.Callback() {
private void callFailure(Throwable e) {
try {
callback.onFailure(e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(response, retrofit);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(Request request, IOException e) {
callFailure(e);
}
@Override public void onResponse(com.squareup.okhttp.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
});
}
首先创建一个rawCall,看下它的内容:
private com.squareup.okhttp.Call createRawCall() {
return retrofit.client().newCall(requestFactory.create(args));
}
很明显这里就是调用OkHttpClient的newCall()方法,然后再调用这个rawCall的enqueue方法,可以看出Retrofit的底层还是调用的OkHttpClient的内容,只不过做了一些封装而已。
到此关于Retrofit的原理分析完毕~
总结一下:
使用Retrofit主要分为三步,第一步通过Retrofit.Builder构造者构造一个Retrofit对象,在这里面主要来给Retrofit中的属性client、ConverterFactory、base_url来赋初始值,然后调用build()方法完成构建,在build()中主要做了两件事,一是创建一个CallAdapter.Factory对象并放倒List中保存,二是建一个用于存放Converter.Factory的List。
第二步就是执行这个retrofit.create()方法,在这个方法中首先创建创建一个MethodHandler对象,在创建MethodHandler的过程中通过上一步的CallAdapter.Factory对象来创建一个CallAdapter对象,然后通过Converter.Factory的fromResponseBody()方法来创建一个Converter对象,放倒之前创建的List中保存。
第三步,当我们去执行具体方法的时候,实际上会调用到这个CallAdapter的adapt(call)方法,它的参数是一个OkHttpCall,这个方法会返回一个新的Call对象ExecutorCallbackCall,ExecutorCallbackCall可以理解为在OkHttpCall外面包了一层,它持有原来的OkHttpCall对象。然后当我们去调用enqueue方法的时候,在这里实际上会调用内部的OkHttpCall对象的enqueue()方法,OkHttpCall的enqueue方法中回去调用okHttpClient的newCall方法创建一个call,然后再去调用这个新call的enqueue方法。这样最终将我们的请求交给了底层的OkHttpClient来处理。