Android-retrofit源码解析

server/2025/2/6 22:04:05/

目录

一,前言

二,使用

三,源码分析


一,前言

retrofit是目前比较流行的网络框架,但它本身并没有网络请求的功能,网络请求的功能是由okhttp来完成的。retrofit只是负责网络请求接口的封装,让我们更加方便的请求网络。

在对retrofit框架进行了解之前,我们需要先了解okhttp,另外retrofit涉及到的设计模式很多,我们主要要了解动态代理模式和适配器模式。

Android-okhttp详解-CSDN博客

Java 代理模式之静态代理与动态代理_java静态代理模式-CSDN博客

Android设计模式--适配器模式_android 适配器模式-CSDN博客

二,使用

在build.gradle配置引用:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

创建数据类:

data class ArticleBean (val chapterName :String,val link :String
)

创建请求接口:

interface YzTestService {@GET("article/list/0/{name}")fun yzTest(@Path("name") name:String?): Call<List<ArticleBean>>
}

在activity使用:

class CommonActivity : AppCompatActivity() {var url = "https://www.wanandroid.com"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_common)val retrofit =Retrofit.Builder().baseUrl(url).addConverterFactory(GsonConverterFactory.create()).build()val service =retrofit.create(YzTestService::class.java)val repos:Call<List<ArticleBean>> = service.yzTest("json")repos.enqueue(object :Callback<List<ArticleBean>>{override fun onResponse(call: Call<List<ArticleBean>>, response: Response<List<ArticleBean>>) {Log.d("yz","请求成功:"+response.body().toString())}override fun onFailure(call: Call<List<ArticleBean>>, t: Throwable) {Log.d("yz","请求失败:"+t.toString())}})}
}

三,源码分析

分析源码一般是从使用入手,一般是着眼于最核心的代码。

从使用分析,我们先看repos.enqueue它的源码:

void enqueue(Callback<T> callback);

结果是个抽象方法,所以我们继续往上看它的使用service.yzTest("json"),这个是我们自己创建的,然后接着往上看retrofit.create(YzTestService::class.java)的源码:

public <T> T create(final Class<T> service) {//判断是否接口 不是接口抛出异常validateServiceInterface(service);return (T)//动态代理模式Proxy.newProxyInstance(//第一个参数 任意的类加载器service.getClassLoader(),//第二个参数 传入的service的class对象new Class<?>[] {service},//第三个参数 静态内部类 new InvocationHandler() {private final Platform platform = Platform.get();private final Object[] emptyArgs = new Object[0];//最主要的方法 @Overridepublic @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);}});
}

然后就来看看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 = ServiceMethod.parseAnnotations(this, method);//加入到缓存serviceMethodCache.put(method, result);}}return result;
}

接着继续看ServiceMethod.parseAnnotations(this, method)这个方法:

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//获取方法的注解信息等 创建请求工厂 里面包含请求的url,请求方式,请求参数等等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);
}

如果符合判断条件,则走HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)

看看这个类:

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT>

它继承了ServiceMethod这个类,我们在看loadServiceMethod(method).invoke(args)的invoke的方法时,发现它是ServiceMethod的抽象方法,然后我们又看到了HttpServiceMethod这个类继承了ServiceMethod,所以我们在HttpServiceMethod这个类里面找一下invoke这个方法,它就是ServiceMethod的具体实现:

@Override
final @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);
}

然后看它的adapt方法:

protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

它是HttpServiceMethod的一个抽象方法,所以我们只能倒回去看 OkHttpCall这个类:

final class OkHttpCall<T> implements Call<T>

发现它是继承了Call,就是上面我们说的:

void enqueue(Callback<T> callback);

这个抽象方法。

所以我们看看OkHttpCall这个类里面enqueue这个方法的具体实现:

@Override
public void enqueue(final Callback<T> callback) {Objects.requireNonNull(callback, "callback == null");okhttp3.Call call;Throwable failure;synchronized (this) {if (executed) throw new IllegalStateException("Already executed.");executed = true;call = rawCall;failure = creationFailure;if (call == null && failure == null) {try {//创建okhttp3的Callcall = rawCall = createRawCall();} catch (Throwable t) {throwIfFatal(t);failure = creationFailure = t;}}}if (failure != null) {callback.onFailure(this, failure);return;}if (canceled) {call.cancel();}call.enqueue(new okhttp3.Callback() {@Overridepublic 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}}@Overridepublic 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}}});
}

上面的代码都很简单,主要就是创建了一个okhttp3的Call,并用这个Call对象去请求网络

创建对象的代码为:

call = rawCall = createRawCall();

还有一个主要方法就是:

response = parseResponse(rawResponse);

这行代码主要就是解析返回的数据。具体代码比较简单,就是数据的具体解析。这里就不做具体分析了。

最重要的方法就是:

callback.onResponse(OkHttpCall.this, response);callback.onFailure(OkHttpCall.this, e);

这两个回调就是我们使用的回调。这样整个流程就通了。

看完主线之后,再来看看上面没有看的HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)这个方法:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;boolean continuationWantsResponse = false;boolean continuationBodyNullable = false;Annotation[] annotations = method.getAnnotations();Type adapterType;
//判断是否支持kotlin挂起方法if (isKotlinSuspendFunction) {Type[] parameterTypes = method.getGenericParameterTypes();Type responseType =Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {// Unwrap the actual body type from Response<T>.responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);continuationWantsResponse = true;} else {// TODO figure out if type is nullable or not// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)// Find the entry for method// Determine if return type is nullable or not}adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);} else {adapterType = method.getGenericReturnType();}
// 关键代码 创建CallAdapterCallAdapter<ResponseT, ReturnT> callAdapter =createCallAdapter(retrofit, method, adapterType, annotations);Type responseType = callAdapter.responseType();if (responseType == okhttp3.Response.class) {throw methodError(method,"'"+ getRawType(responseType).getName()+ "' is not a valid response body type. Did you mean ResponseBody?");}if (responseType == Response.class) {throw methodError(method, "Response must include generic type (e.g., Response<String>)");}// TODO support Unit for Kotlin?if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {throw methodError(method, "HEAD method must use Void as response type.");}Converter<ResponseBody, ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType);okhttp3.Call.Factory callFactory = retrofit.callFactory;if (!isKotlinSuspendFunction) {return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);} else if (continuationWantsResponse) {//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.return (HttpServiceMethod<ResponseT, ReturnT>)new SuspendForResponse<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);} else {//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.return (HttpServiceMethod<ResponseT, ReturnT>)new SuspendForBody<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,continuationBodyNullable);}
}

从上面的代码中我们提取出一个关键代码:createCallAdapter,来看看它的源码:

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {try {//noinspection uncheckedreturn (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);}
}

接着往下看retrofit.callAdapter:

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {return nextCallAdapter(null, returnType, annotations);
}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;}}StringBuilder builder =new StringBuilder("Could not locate call adapter for ").append(returnType).append(".\n");if (skipPast != null) {builder.append("  Skipped:");for (int i = 0; i < start; i++) {builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());}builder.append('\n');}builder.append("  Tried:");for (int i = start, count = callAdapterFactories.size(); i < count; i++) {builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());}throw new IllegalArgumentException(builder.toString());
}

这里面没有什么有用的代码 关键就是callAdapterFactories.get(i).get(returnType, annotations, this);这个方法,我们先看下callAdapterFactories是什么:

final List<CallAdapter.Factory> callAdapterFactories;

再看下它在哪里赋值的:

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);
}

这个就是在我们使用的时候,调用Retrofit.build方法的时候,赋值的。

具体看下它的赋值内容:

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));

因为我们是android平台 所以我们直接查看platform.defaultCallbackExecutor()找android平台就能看到它的具体实现:

@Override
public Executor defaultCallbackExecutor() {return new MainThreadExecutor();
}
static final class MainThreadExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());@Overridepublic void execute(Runnable r) {handler.post(r);}
}

这个就是切换到了主线程。

然后我们回到上面看看callAdapterFactories.get(i).get(returnType, annotations, this);的方法:

@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 =Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)? null: callbackExecutor;return new CallAdapter<Object, Call<?>>() {@Overridepublic Type responseType() {return responseType;}@Overridepublic Call<Object> adapt(Call<Object> call) {return executor == null ? call : new ExecutorCallbackCall<>(executor, call);}};
}

然后我们就发现了adapt方法,我们回到前面的代码:

@Override
final @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);
}

这个里面的adapt就是上面的adapt,它把OKHttpcall又包了一层,具体看看怎么包装的:

static final class ExecutorCallbackCall<T> implements Call<T> {final Executor callbackExecutor;//传入的android平台的executor 用于切换主线程final Call<T> delegate; //OKHttpCallExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {this.callbackExecutor = callbackExecutor;this.delegate = delegate;}@Overridepublic void enqueue(final Callback<T> callback) {Objects.requireNonNull(callback, "callback == null");delegate.enqueue(new Callback<T>() {@Overridepublic 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.//调用者传入的callbackcallback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {//调用者传入的callbackcallback.onResponse(ExecutorCallbackCall.this, response);}});}@Overridepublic void onFailure(Call<T> call, final Throwable t) {callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));}});}@Overridepublic boolean isExecuted() {return delegate.isExecuted();}@Overridepublic Response<T> execute() throws IOException {return delegate.execute();}@Overridepublic void cancel() {delegate.cancel();}@Overridepublic boolean isCanceled() {return delegate.isCanceled();}@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.@Overridepublic Call<T> clone() {return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());}@Overridepublic Request request() {return delegate.request();}@Overridepublic Timeout timeout() {return delegate.timeout();}
}

这样就在内部结果返回时自动切换到了主线程,避免了用户自己切换线程的麻烦。


http://www.ppmy.cn/server/165514.html

相关文章

面向npm的实时仪表板Dashly

之前介绍过读取 npm 日志的 GoAccess&#xff0c;这次介绍的是能动态跟踪和显示您 npm 中所有服务的轻量级实时仪表板 – Dashly 简介 什么是 Dashly &#xff1f; Dashly 是一个为 Nginx Proxy Manager 用户定制的实时仪表板。它通过自动与 NPM 数据库同步来简化您监控和组织…

Java 2024年面试总结(持续更新)

目录 最近趁着金三银四面了五六家公司吧&#xff0c;也整理了一些问题供大家参考一下&#xff08;适合经验三年左右的&#xff09;。 面试问题&#xff08;答案是我自己总结的&#xff0c;不一定正确&#xff09;&#xff1a; 总结&#xff1a; 最近趁着金三银四面了五六家公…

小程序项目-购物-首页与准备

前言 这一节讲一个购物项目 1. 项目介绍与项目文档 我们这里可以打开一个网址 https://applet-base-api-t.itheima.net/docs-uni-shop/index.htm 就可以查看对应的文档 2. 配置uni-app的开发环境 可以先打开这个的官网 https://uniapp.dcloud.net.cn/ 使用这个就可以发布到…

mysqldump+-binlog增量备份

注意&#xff1a;二进制文件删除必须使用help purge 不可用rm -f 会崩 一、概念 增量备份&#xff1a;仅备份上次备份以后变化的数据 差异备份&#xff1a;仅备份上次完全备份以后变化的数据 完全备份&#xff1a;顾名思义&#xff0c;将数据完全备份 其中&#xff0c;…

机器学习中的关键概念:通过SKlearn的MNIST实验深入理解

欢迎来到我的主页&#xff1a;【Echo-Nie】 本篇文章收录于专栏【机器学习】 1 sklearn相关介绍 Scikit-learn 是一个广泛使用的开源机器学习库&#xff0c;提供了简单而高效的数据挖掘和数据分析工具。它建立在 NumPy、SciPy 和 matplotlib 等科学计算库之上&#xff0c;支持…

如何用微信小程序写春联

​ 生活没有模板,只需心灯一盏。 如果笑能让你释然,那就开怀一笑;如果哭能让你减压,那就让泪水流下来。如果沉默是金,那就不用解释;如果放下能更好地前行,就别再扛着。 一、引入 Vant UI 1、通过 npm 安装 npm i @vant/weapp -S --production​​ 2、修改 app.json …

Docker 部署 Starrocks 教程

Docker 部署 Starrocks 教程 StarRocks 是一款高性能的分布式分析型数据库&#xff0c;主要用于 OLAP&#xff08;在线分析处理&#xff09;场景。它最初是由百度的开源团队开发的&#xff0c;旨在为大数据分析提供一个高效、低延迟的解决方案。StarRocks 支持实时数据分析&am…

【MyDB】4-VersionManager 之 3-死锁及超时检测

【MyDB】4-VersionManager 之 3-死锁及超时检测 死锁及超时检测案例背景LockTable锁请求与等待管理 addvm调用addputIntoList&#xff0c;isInList&#xff0c;removeFromList 死锁检测 hasDeadLock方法资源释放与重分配 参考资料 死锁及超时检测 本章涉及代码&#xff1a;top/…