初探retrofit网络请求框架
retrofit简介
retrofit是由square公司的大神开发的一个网络请求适配器框架,这个框架简化了对okhttp的使用,它将一个基本的Java接口通过动态代理的方式翻译成一个HTTP请求,并通过OkHttp去发送请求。此外它还具有强大的可扩展性,支持各种格式转换以及RxJava。本文是基于Retrofit 2.9.0 版本去分析的。
retrofit的简单使用
这里我们只是展示一下retrofit的简单使用,主要函数为我们分析源码提供入口
//创建接口服务
interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
//配置retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
//发起网络请求
Call<List<Repo>> repos = service.listRepos("你的github账户");
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
Log.i("guojingbu", "onResponse: 成功" + new Gson().toJson(response.body()));
Log.i("guojingbu","thread = "+Thread.currentThread().getName());
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
Log.i("guojingbu", "onResponse: 失败");
}
});
关键类说明
Retrofit:retrofit框架的总的配置入口,最关键的方法是create方法能够体现retrofit框架的整体结构
OkHttpCall:主要负责的是构建并代理okhttp的call对象进行网络请求以及结果的解析然后回调出去。
CallAdapter:主要是用来处理把okhttp请求回来的回调切换到主线程执行,但它不仅仅是单纯的做线程切换他还可以适配rxjava,以及对kotlin协程调用的支持等
ParameterHandler:这个类主要是对我们定义的请求结构的一些参数的处理类
ExecutorCallbackCall:主要是把okhttp请求结果的子线程回调切换到主线程
retrofit 源码分析
public <T> T create(final Class<T> service) {
//省略...
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//省略...
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
Platform.get()这个方法主要是用户获取平台信息的retrofit根据不同的平台会有不同的处理,这里我们关注一下,下面分析retrofit切换线程的时候会用到。
create()方法是通过动态代理方式来创建我们请求接口的代理类,然后通过loadServiceMethod(method)加载我们创建的请求接口方法,loadServiceMethod这个方法的主要逻辑是利用map集合缓存我们的请求接口方法提高性能。
ServiceMethod<?> loadServiceMethod(Method method) {
//...省略缓存相关的代码
result = ServiceMethod.parseAnnotations(this, method);
//....省略缓存相关的代码
}
}
return result;
}
这一段代码我们主要关注parseAnnotations方法,这个方法主要解析我们定义的请求接口的注解信息和方法信息。最终它会调到HttpServiceMethod类中的parseAnnotations()方法。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//...省略一些与切换线程无关的和类型参数校验的逻辑
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
//...
}
在这个方法中我们可以看到一个CallAdapter类,那这个类是什么呢?我们进入createCallAdapter()方法看一下
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
//...
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
//...
}
它里面调用的是retrofit中的callAdapter()方法,我们一直跟下去发现它会调用Retrofit类的nextCallAdapter()方法,我们来看一下这个方法做了什么
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
//注意这个一行代码下面会用到
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//...省略一些处理异常的代码
}
从这个方法可以看出它是从callAdapterFactories这个List的集合中遍历去取CallAdapter,那么callAdapterFactories这个list集合是在哪初始化的呢?通过我们查找发现是在Retrofit采用build模式,我们来看一下它的build方法
public Retrofit build() {
//...省略一些异常判断
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//...省略一些convert相关的代码,这里我们暂不分析.
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
从这一段代码中可以看出它是调用了platform中的defaultCallAdapterFactories()方法来初始化的,跟进去发现它会创建一个DefaultCallAdapterFactory工厂对象。这个类中主要关注一下它的get()方法
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
//...省略一些类型的判断逻辑
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
在这个get方法中我们可以看到有一个CallAdapter匿名内部类的实现,在adapt中会返回一个ExecutorCallbackCall对象,这个类就是我们要找的线程切换相关的类了,这个类实现了是retrofit的Call接口。
static final class ExecutorCallbackCall<T> implements Call<T> {
//...省略一些不相关的代码
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
//...省略一些不相关的代码
}
通过这一段代码我们就会发现他是通过callbackExecutor这个执行器来切换线程的。那这个参数是从哪来的呢?其实是在我们调用retrofit的build方法传进来的那我们在来看一下retrofit的build方法中callbackExecutor是怎么得到的。
public Retrofit build() {
//...省略不相关的代码
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//...省略不相关的代码
}
一层一层跟进platform.defaultCallbackExecutor()这个方法,会发现最终会调用Android的这个实现类的defaultCallbackExecutor()方法。最终通过主线程的Handler来把请求的回调切换到主线程来执行。
static final class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//...省略无关代码
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
以上就是retrofit是怎么切换的线程的流程。
接下来我们再来分析一下retrofit是怎么调用okhttp进行网络请求的。这里其实我们只需要关注一下retrofit的Call接口的enqueue()方法。这里我们知道retrofit的Call是一个接口,那么我应该看哪个实现类呢?通过上面的分析我们就能确定我们应该看OkHttpCall这个实现类的enqueue()方法
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
//...
call = rawCall = createRawCall();
//...
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
在这个方法中我们可以看到调用了createRawCall()方法,这个方法主要是构建真实用户网络请求的okhttp的call对象,
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
我们往上追踪代码你会发现上面代码中的callFactory其实就是OkHttpClient如果我们在构建retrofit时候不传OkHttpClient它会默认创建一个,这时候通过okhttpclient的newCall()我们就会得到一个真正用于网络请求的okhttp的Call对象。在上面enqueue方法中的callback回调其实并不一定是我们使用retrofit的传进来的回调callback,有可能是我们通过CallAdapter适配切换线程后返回的回调函数callback。
至于数据的解析这个其实就是我们在创建Retrofit对象时设置的GsonConverterFactory这个类通过responseBodyConverter()创建了一个GsonResponseBodyConverter的类,这个类中有一个convert的方法负责把请求回来的数据转为你想要的的类型。这里我们就不再分析了,大家可以自行了解。
总结
retrofit这个框架整个结构还是相对简单的,但是如果深入到细节还是比较复杂的,这篇文章我们主要看了下retrofit的整体结构,具体实现还需要再研究研究。