提示:文章比较长,可能需要较长时间阅读理解。
一.如何使用Retrofit
首先需要在gradle配置里面增加对retrofit的引用。
compile'com.squareup.retrofit2:retrofit:2.2.0'
我下载到的版本是2.2.0的版本。
首先来看一下Retrofit是怎么用的。
public interface GithubService{
@GET("user/{user}/repos")
Call<List<ResponseBody>> listRpo(@Path("user") String user)
}
Retrofit tetrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.baseUrl("https://www.github.com/")
.build();
GithubService service = tetrofit.create(GithubService.class)
Call<List<ResponseBody>> call = service.listRpo("octocat");
call.enqueue(new Callback<List<ResponseBody>>() {
@Override
public void onResponse(Call<List<ResponseBody>> call, Response<List<ResponseBody>> response) {
String result = response.getBody();
}
@Override
public void onFailure(Call<List<ResponseBody>> call, Throwable t) {
Log.d("TAG",t.getMessage());
}
});
使用retrofit需要先创建一个interface接口,这个接口声明了网络请求的地址,参数,返回类型,请求方式等等。
我们看到接口的请求方法必须要用retrofit的注解来标注,而这个接口用于描述创建网络请求。
Retrofit提供的接口支持以下注解的功能:
1.@GET 和 @Post支持切换请求方式
2.@Path支持请求格式的动态变化,@Header用于添加不固定的Header
3.支持FormUrlEncoded和Multipart等标记
而当Retrofit访问网络时,大概流程分为1.构建网络请求 2.发送网络请求 两步骤。
1.构建网络请求——创建一个Retrofit类,这个Retrofit类是用建造者模式构建的。baseUrl()方法指定访问的URL。(Retrofit会讲baseurl和接口定义的url做拼接,才是最后的url)然后获得GithubService对象,这个GithubService对象其实就是我们自己定义的接口类,Retrofit会自动将我们定义的接口类转化成网络请求。
2.发送网络请求——得到Call对象,执行Call对象。
二.构建网络请求
接下来从源码的角度来分析一下内部原理,首先来看一下Retrofit类。
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final Executor callbackExecutor;
final boolean validateEagerly;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
最核心的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);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
先来看一下build方法,调用Retrofit.build的build方法会生成一个Retrofit对象,通过建造者模式(建造者模式:构建和使用相分离)传递给它callFactory, baseUrl, converterFactories, adapterFactories这些参数,
callFacotry表示网络请求采用的底层通信,表示存放网络请求的工厂
baseUrl这个很好理解,表示请求的地址
converterFactories表示存放数据转换器的工厂,用于解析服务端返回的数据,比如像常见的Gson,json数据格式等。
adapterFactories表示存放适配转换器的工厂,因为retrofit支持rxjava、java8等平台语,所以这个工厂列表主要用来生产适配转换器。
当我们通过建造者模式构建好Retrofit实例后,然后调用它的create的方法,传入一个接口。
create方法是非常重要核心的方法,在create方法中首先会进行判断所传入进来的Service是否是一个接口,当我们将validateEagerly属性设为true的时候,在我们调用create方法创建一个Service,会调用eagerlyValidateMethods方法里面。eagerlyValidateMethods里面进行了什么操作?它通过反射获取获们创建service接口中所有的接口方法,然后根据接口方法和当前的retrofit对象来获得ServiceMethod并且以接口方法作为Key,ServiceMethod作为值添加到serviceMethodCache缓存中。这样做的目的是为了下次便可以通过接口方法直接获取ServiceMethod。这就是 eagerlyValidateMethods的作用。
继续分析create方法里面的代码,接着往下看
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
这里用到了java的动态代理,java动态代理的作用是将这个在一段代码的方法执行前插入一段执行的代码。
关于java的动态机制,网上有很多比较好的文章,这里也有一篇文章推荐。
那么,当我们通过自己创建的接口去调用接口方法时,这时候动态代理会去先执行invoke方法。那么究竟利用动态代理invoke了什么代码呢?在InvocationHandler的invoke方法里面,我们可以看到执行了下面的代码。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod
(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
invoke里面的这三句代码是整个retrofit的核心代码。ServiceMethod负责将自定义接口转化为实际的http请求。
然后再调用servicemehtod的calladapter当中的adapt方法进行初始化。
也就是说当我们调用自己实现接口的方法时,Retrofit利用create方法然后通过java动态放射的方式去调用servicemethod当中的calladapter当中的adapt方法进行初始化。
这样就得到的动态代理接口看起来是上面自己实现的GithubService,但是通过java动态代理会将这个GithubService在调用方法时转化为真正的http请求。
通过loadServceMethod方法从这个缓存当中获取ServiceMethod。
loadServceMethod方法首先去缓存里面去取ServcieMethod,如果没有,调用ServiceMehtod的build()方法。
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
...//省略代码 return new ServiceMethod<>(this);
}
这ServiceMethod的build方法里面调用了createCallAdapter方法创建calladapter对象。
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
里面是调用了Retrofit类的callAdapter方法。
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
原来createCallAdapter里面默认遍历了Retrofit的adapterFactories,但是Retrofit当中有哪些CallAdapter呢?
回过头来再去看Retrofit类的build方法,Retrofit类在build方法中返回一个默认的defaultCallAdapterFactory。
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
也就是说,不管Retrofit有没有往adapterFactories里面增加CallAdapter对象,都有一个默认的defaultCallAdapterFactory。
Retrofit在创建的时候,默认的callFactory是OKHttpClient,默认的callbackexecutrot是platform.defaultCallbackExecutor();
platform是一个retrofit里面表示当前平台的接口,在Android设备中,这个paltform是一个Android类里实现的,我们在下面这段代码中找到了这个defaultCallbackExecutor.
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
@Nullable Executor defaultCallbackExecutor() {
return null;
}
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
通过分析上面的源代码,这里不难理解,platform对象默认返回的是Android对象,所以我们再看一下Android类的代码
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor(); }
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor); }
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) { handler.post(r); }
}
}
看defaultCallAdapterFactory这个方法返回的是ExecutorCallAdapterFactory
我们看一下ExecutorCallAdapterFactory的源码。
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
得出结论:serviceMethod.callAdapter.adapt(okHttpCall);
最终返回了一个ExecutorCallbackCall。
三,发送网络请求
ExecutorCallbackCall就是一个Call对象,java动态代理帮助我们构建了一个完整的http请求,并最终返回了
一个Call对象,我们先来看一下它的源代码。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
ExecutorCallbackCall有enqueue和execute方法,但是具体里面都是交给delegate对象去执行的。那么这个delegate对象又是什么呢?就是serviceMethod.callAdapter.adapt(okHttpCall)里面的okHttpCall,一个实现了Call接口的OkHttpCall对象。看到这里是不是有一种恍然大悟的感觉:Retrofit的本质是通过okhttp来完成,我们只要研究下OkHttpCall对象就行了。
OkHttpCall对象的代码主要有两个重要函数,enqueue方法和execute方法。
这两个方法最后是通过调用createRawCall()来创建请求
privateokhttp3.Call createRawCall()throwsIOException {
Request request =serviceMethod.toRequest(args);
okhttp3.Call call =serviceMethod.callFactory.newCall(request);
if(call == null) {
throw newNullPointerException("Call.Factory returned null.");
}
return call;
}
execute方法代表是在当前线程执行,而相对于execute方法,enqueue方法则是将请求放到一个异步线程队列当中。
下面的代码是HttpCall里面的execute方法
@OverridepublicResponse<T> execute() throwsIOException {
okhttp3.Call call;
synchronized(this) {
if(executed)throw newIllegalStateException("Already executed.");
executed=true;
if(creationFailure!=null) {
if(creationFailureinstanceofIOException) {
throw(IOException)creationFailure;
}else{
throw(RuntimeException)creationFailure;
}
}
call =rawCall;
if(call ==null) {
try{
call =rawCall= createRawCall();
}catch(IOException | RuntimeException e) {
creationFailure= e;
throwe;
}
}
}
if(canceled) {
call.cancel();
}
returnparseResponse(call.execute());
}
可以看到,最后是执行了okhttp.Call.execute方法。
四,支持报文解析
Retrofit还支持Gson、xml格式报文解析 。比如我们想加入gson格式的解析,只需在构建的时候调用addConvertFactory方法。
Retrofit retrofit = new Retrofit.Builder().
baseUrl('https://api.github.com').
.addConvertFacotry(GsonConverterFactory.create()) //支持报文自动解析
.build
然后构建网络请求:
final MehtodService methdoservice = retrofit.create(MehtodService.s);
发起网络请求
Call<Bean> call = methdoservice.getMsg();
GsonConverterFacotry会自动解析你接受的gson格式的报文,在调用网络请求后,转化成为这里的Bean。
Bean类里面的字段和Gson报文返回的字段应该一样。如果字段不一样,会在解析的时候抛出解析异常。
如果想让你的Retrofit支持自动解析的方法,就必须先引入所需的第三方库:
如果想要增加对xml解析器的支持:
compile(‘com.squareup.retrofit2:converter-simplexml:2.1.0’);
如果想要增加对gson格式解析器的支持:
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
如果想要增加对rxjava的支持:
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
也可以通过实现Converter.Factory接口来创建一个自定义的converter。addConvertFacotry里面的操作就是往Retrofit这个类中增加Converter.Factory接口.
这个Converter对象是什么时候创建的?首先我们在构建Retrofit的时候传了一个GsonConverterFactory.create(),然后会在ServiceMethod的build()的时候将我们创建的Converter加入进去.关键代码如下:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
。。。
}
关键是执行了createResponseConverter()方法,然后查看你createResponseConverter方法
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
主要执行了responseBodyConverter方法。找到responseBodyConverter方法再看一下()。
public<T> Converter<ResponseBody, T>responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
看下nextResponseBodyConverter()这里面的逻辑。
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
。。。
}
从上面的代码可以知道,关键点是执行了从converterFactories当中查找到对应的factory,然后执行responseBodyConverter方法,如果这个factory是GsonConverterFactory,则执行GsonConverterFactory的responseBodyConverter方法.
如果是自定义的Converter.Factory,就是自己实现这个方法。
五,支持rxjava
Retrofit2支持了RxJava的使用。
首先需要在build.gradle当中加入
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
然后在Retrofit的构造时候加入对rxjava的支持
Retrofit tetrofit = new Retrofit.Builder()
.addCallAdapterFactory( RxJavaCallAdapterFactory.create())
好了。
那么它里面是怎么实现的呢?RxJavaCallAdapterFactory里面有个get方法,具体方法如下
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//..
//省略了部分源码,
//通过getCallAdapter来获取Adapter
CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
return callAdapter;
}
接着看一下getCallAdapter方法
//获取CallAdapter<Observable<?>>
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
//..
//省略了部分源码,
//一般会走SimpleCallAdapter
return new SimpleCallAdapter(observableType, scheduler);
}
SimpleCallAdapter的源码如下:
static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
private final Type responseType;
private final Scheduler scheduler;
SimpleCallAdapter(Type responseType, Scheduler scheduler) {
this.responseType = responseType;
this.scheduler = scheduler;
}
@Override public Type responseType() {
return responseType;
}
@Override public <R> Observable<R> adapt(Call<R> call) {
//通过Observable.create创建被观察者
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);//切换到指定线程
}
return observable;
}
}
六,总结
Retrofit是一款热门的网络请求架构,拓展性非常好。理解这样的开源框架的源码,有助于我们扩展视野,以及更好解决在实际开发过程当中所遇到的问题。