Retrofit原理解析
source link: https://www.longdw.com/retrofit2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
retrofit和okhttp都是用来做网络请求的,并且都是出自Square公司。其中okhttp是用来代替android原生的HttpClient和HttpURLConnection的,官方也是建议用okhttp作为android底层的网络通信库。而retrofit将okhttp进一步封装,让开发者更方便的做网络请求。
通过本章的学习我们能够了解并掌握:
- retrofit整体框架
- retrofit是如何封装okhttp来做请求的?
- retrofit如何做数据解析的?
retrofit整体框架
先根据官网的教程,写一个简单的例子:
//1.申明接口 interface GitHubService { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String?): Call<List<Repo>> fun listRepos2(@Path("user") user: String?): Single<List<Repo>> } //2.创建retrofit val retrofit = Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .baseUrl("https://api.github.com/") .build() //3.实现接口 val service = retrofit.create(GitHubService::class.java) //4.调用接口 val repos: Call<List<Repo>> = service.listRepos("longdw") //5.发起请求 repos.enqueue(object: Callback<List<Repo>> { override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) { println("response-->${response.body()!![0].name}") } override fun onFailure(call: Call<List<Repo>>, t: Throwable) { } })
只需要简单的5个步骤,就能够实现请求网络并将服务器返回的数据解析成对象,并且能直接在onResponse()
和onFailure()
回调方法里面直接操作UI。
是不是简单方便又高效,但是当我尝试进入enqueue()
方法或者listRepos()
方法查看具体调用过程时,都是接口,没法看具体的实现类,这可咋办呢?也就是说第4、5步走不下去了。那我们就从第3步开始看起。
public final class Retrofit { ... public <T> T create(final Class<T> service) { validateServiceInterface(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 { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); } ... ServiceMethod<?> loadServiceMethod(Method method) { ServiceMethod<?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); } } return result; } }
上面选取部分Retrofit源码,其中create()方法是Retrofit的核心,该方法有两个关键点:
(1)validateServiceInterface(service)
该方法我没贴出来,主要作用是验证我们写的接口有没有问题,比如接口不能有泛型。大家看源码后会发现该方法里面有个validateEagerly
关键字,默认是false,如果设置为true的话,会在接口中的方法还没调用的时候,也就是只在我们调用retrofit.create()
的时候就开始检查所有方法是否合法了。所以我们在生产环境不要开启这个,否则可能会导致应用启动速度慢,如果接口中有很多方法,还有可能会导致ANR等问题。
(2)Proxy.newProxyInstance()
这个就是我们常看到或者听到的动态代理,有3个参数:ClassLoader、Class数组、InvocationHandler匿名类。其中就Retrofit
来讲,第二个参数传的是GitHubService,其基本原理就是当我们调用此接口中的方法时,比如上例中的listRepos()
方法,动态代理会最终调用InvocationHandler
匿名类中的invoke(Object proxy, Method method, @Nullable Object[] args)
方法。用伪代码表示就是长下面这样:
public class GitHubServiceImpl implements GitHubService { InvocationHandler invocationHandler = 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 { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }; @NonNull @Override public Call<List<Repo>> listRepos(@Nullable String user) { Method method = GitHubService.class.getMethod("listRepos", String.class); return invocationHandler.invoke(this, method, user); } }
通过上面的介绍,我们了解到Retrofit的核心实际上就是运用了动态代理作为桥梁,当我们调用接口方法时,动态代理会自动创建一个类作为代理类,用代理类来包装我们的请求。
retrofit是如何封装okhttp来做请求的?
本小结重点来讲解下代理类中都干了些啥。首先判断如果调用的方法是Object中的方法,比如toString()
、hashCode()
等,就直接调用,否则调用loadServiceMethod(method).invoke(args)
。
loadServiceMethod(method)
里面,通过ServiceMethod.parseAnnotations()
解析出接口方法的注解、传入的参数、返回的参数等信息,最终以HttpServiceMethod
类型返回,并用serviceMethodCache
缓存起来。通过调用HttpServiceMethod
的invoke()
方法来包装请求的过程以及数据解析的过程。
接下来从invoke()
寻找突破口,先看ServiceMethod
类。
abstract class ServiceMethod<T> { static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); Type returnType = method.getGenericReturnType(); if (Utils.hasUnresolvableType(returnType)) { throw methodError( method, "Method return type must not include a type variable or wildcard: %s", returnType); } if (returnType == void.class) { throw methodError(method, "Service methods cannot return void."); } return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } abstract @Nullable T invoke(Object[] args); }
再看HttpServiceMethod
类。
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> { static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); ... Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else ... } private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { try { //noinspection unchecked return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create call adapter for %s", returnType); } } private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create converter for %s", responseType); } } HttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { this.requestFactory = requestFactory; this.callFactory = callFactory; this.responseConverter = responseConverter; } @Override final @Nullable ReturnT invoke(Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args); static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { private final CallAdapter<ResponseT, ReturnT> callAdapter; CallAdapted( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; } @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) { return callAdapter.adapt(call); } } }
以上是HttpServiceMethod
的核心代码,loadServiceMethod(method).invoke(args)
最终调用的是HttpServiceMethod
的invoke()
方法,主要做了两件事:
(1)创建OkHttpCall对象
final class OkHttpCall<T> implements Call<T> { OkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this.requestFactory = requestFactory; this.args = args; this.callFactory = callFactory; this.responseConverter = responseConverter; } private okhttp3.Call getRawCall() { okhttp3.Call call = rawCall; return rawCall = createRawCall(); } private okhttp3.Call createRawCall() throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); return call; } @Override public void enqueue(final Callback<T> callback) { okhttp3.Call call; call = rawCall = createRawCall(); if (failure != null) { callback.onFailure(this, failure); return; } call.enqueue( new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; response = parseResponse(rawResponse); callback.onResponse(OkHttpCall.this, response); } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { callback.onFailure(OkHttpCall.this, e); } }); } Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); } }
OkHttpCall
类里面同样也有几个需要关注的重点
a)enqueue()
方法,Call
通过此方法来发起调用。
b)通过callFactory.newCall()
来创建真正的发起网络请求的Call
。
c)通过responseConverter.convert()
来解析服务器返回的数据。
这几个方法等会再详细介绍,先继续往下看。
(2)调用adapt()方法
实际上调用的是CallAdapted.adapt()
方法,接着执行callAdapter.adapt(call)
。看上面HttpServiceMethod
源码我们得知,callAdapter
实际上是retrofit.callAdapter()
创建的。接着我们再看Retrofit
源码:
public final class Retrofit { Retrofit( okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = converterFactories; // Copy+unmodifiable at call site. this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; } public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { 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; } } } public static final class Builder { 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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>( 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize()); // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); converterFactories.addAll(platform.defaultConverterFactories()); return new Retrofit( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } } }
看到这里我们得停下来,思考下我们的初衷是什么,我们的目的是要找到callAdapter
是如何创建的,进而找到adapt()
方法的逻辑。
仔细阅读上面的源码,callAdapter
是由Builder
的build()
方法创建的callAdapterFactories
创建的。callAdapterFactories
是个集合,默认的callAdapter
是由platform.defaultCallAdapterFactories(callbackExecutor)
创建。callbackExecutor
参数是一个Executor
:
static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } }
defaultCallAdapterFactories()
返回的是DefaultCallAdapterFactory
:
final class DefaultCallAdapterFactory extends CallAdapter.Factory { private final @Nullable Executor callbackExecutor; DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) { this.callbackExecutor = callbackExecutor; } @Override public @Nullable CallAdapter<?, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } if (!(returnType instanceof ParameterizedType)) { throw new IllegalArgumentException( "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>"); } final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType); final Executor executor = 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); } }; } 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) { 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)); } }); } @Override public boolean isExecuted() { return delegate.isExecuted(); } @Override public Response<T> execute() throws IOException { return delegate.execute(); } } }
看到这里大家应该长叹一口气,我们要的CallAdapter
终于找到了。还记得上面callAdapter.adapt(call)
吗?我们就是从这里一步步往下深入源码的,接着再看adapt(call)
,返回的是ExecutorCallbackCall
。哦!原来饶了这么一圈,又给我包装了一个ExecutorCallbackCall
,当我们调用call.enqueue()
时,实际上调用的是这个包装类
里面的ExecutorCallbackCall
enqueue()
,然后该方法内部又调用了间接发起网络请求的OkHttpCall
类中的enqueue()
,最后在OkHttpCall
类的enqueue()
方法内部调用直接发起网络请求的okhttp3.Call
类的enqueue()
。
为啥一个调用要包装两层呢?首先是ExecutorCallbackCall
,这个类里面大家注意看下onResponse()
和onFailure()
这两个回调,不是直接调用callback.xxx()
,而是包装了一层callbackExecutor.execute()
,这个callbackExecutor
就是我们上面贴出来的MainThreadExecutor
,是不是瞬间明白了?没错,就是将回调信息通过主线程返回。
看到这里,相信大家对Retrofit整体的流程应该有了一个清晰的认识了,最后我们再看看前面留下的两个知识点没有深入讲解:
通过callFactory.newCall()
创建okhttp3.Call
,通过responseConverter.convert()
来解析数据。
retrofit如何做数据解析的?
首先讲下callFactory.newCall()
是怎么创建okhttp3.Call
的。
callFactory
其实跟callAdapter
的套路差不多,结合HttpServiceMethod
和Retrofit
源码,找到Builder
类build()
方法中的callFactory
,实际上就是OkHttpClient()
。
最后再讲下responseConverter.convert()
是怎么解析数据的。
同样的套路,找到Builder
类build()
中的converterFactories
集合。还记得我们初始化Retrofit
传入的addConverterFactory(GsonConverterFactory.create())
吗?没错,最终是通过GsonConverterFactory
来解析数据的。
至此,整个Retrofit的原理,包括调用过程以及数据的解析过程都讲解完毕了,当然细节部分比如怎么解析注解和参数等,这些对照源码看下应该都能明白。本篇文章主要还是讲解整个大的框架,先从宏观上把握了整个流程,再去深入源码,就能够掌握更多的细节。不能一开始就抠细节,这样到最后自己都搞晕了,就没信心继续往下看了。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK