妙不可言的Retrofit
作者丨水煮鸡蛋也好吃
来源丨Android开发中文站
https://juejin.im/post/5e44ea086fb9a07c9e1c19b6
前言
噢!亲爱的朋友们,快来看看这优秀的Retrofit,它实在太美妙了,如果你不看的话,我保证会用我的靴子狠狠地踢你的屁股!(狗头保命)正文
1. 什么是Retrofit?
在 官网 中对它的描述:A type-safe HTTP client for Android and Java大概意思也就是针对 Java 和 Android的 一种类型安全的HTTP库.Retrofit是Square开源的一款优秀的网络框架,它不会自己去请求网络,而是对OkHttp进行了封装。仅仅会使用还不够,学习源码有助于我们更好的成长。
2. Retrofit的使用
我们先来看看官网上的案例:先定义你的网络接口public interface GitHubService {创建Retrofit对象
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()获得网络请求API的实例
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);调用API方法
Call<List执行网络请求> call = service.listRepos("octocat");
// 同步至此,Retrofit的一次网络请求就结束了,是不是很简单。Retrofit大大减轻了开发者对于网络请求的操作。
try {
Listrepos = call.execute().body();
} catch (IOException e) {
e.printStackTrace();
}
// 异步
call.enqueue(new Callback<List>() {
@Override
public void onResponse(Call<List> call, Response<List > response) {
// 数据返回成功
}
@Override
public void onFailure(Call<List> call, Throwable t) {
// 数据返回失败
}
});
3.Retrofit的URL和参数类型
3.1 Url规则和配置
支持的协议:GET / POST / PUT / DELETE / HEAD / PATCH比如:@GET("users/{user}/repos")GET中的value 要和baseUrl整合一起我们来看看baseUrl和value的整合规则:
第一种:
path 是 绝对路径形式:path = "/apath", baseUrl = "http://host:port/a/b"
Url = "http://host:port/apath"
第二种:
path 是相对路径,baseUrl 目录形式:path = "apath", baseUrl = "http://host:port/a/b/"
Url = "http://host:port/a/b/apath"
第三种:
path 是相对路径,baseUrl 是文件形式:path = "apath", baseUrl = "http://host:port/a/b"
Url = "http://host:port/a/apath"
第四种:
path 是完整Url:path = "http://host:port/aa/apath", baseUrl = "http://host:port/a/b"建议整个项目都统一使用一种路径方式,一般选择第二种方式。
Url = "http://host:port/aa/apath"
3.2 参数类型
通过注解的形式令Http请求的参数更加直接。3.2.1 Query & QueryMap
Query 其实就是Url 中 ?之后的 key-value。比如:url :"www.println.net/?cate=andro…"其中 cate=android 就是 Query。
interface PrintlnServer{如果拥有多个参数的话 , 可以使用 QueryMap。
@GET("/")
Call<String> cate(@Query("cate") String cate);
}
//参数 cate 就是 它的 key,传入的值 就是它的 value
3.2.2 Field & FieldMap
在项目中,大部分情况下我们是使用POST。@FormUrlEncoded如果 你有多个参数需要填写, 当然可以使用 FieldMap 。
@POST("/")
Callexample(@Field("name") String name,
@Field("occupation") String occupation);
// 需要注意的是 使用Field 的时候,要加 @FormUrlEncoded 用来格式化。
3.2.3 Part & PartMap
用于上传文件案例:public interface FileUploadService {当然如果需要多个Part参数,可以使用PartMap 。接下来我们来看下Retrofit的原理是如何完成的。
@Multipart
@POST("upload")
Callupload(@Part("description") RequestBody description, ;
@Part MultipartBody.Part file)
}
// 注意使用 注解 @Multipart
************************ 使用案例 ***********************
//先创建 service
FileUploadService service = retrofit.create(FileUploadService.class);
//构建要上传的文件
File file = new File(filename);
RequestBody requestFile =
RequestBody.create(MediaType.parse("application/otcet-stream"), file);
MultipartBody.Part body =
MultipartBody.Part.createFormData("aFile", file.getName(), requestFile);
String descriptionString = "This is a description";
RequestBody description =
RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
Callcall = service.upload(description, body);
call.enqueue(new Callback() {
@Override
public void onResponse(Callcall,
Responseresponse) {
System.out.println("success");
}
@Override
public void onFailure(Callcall, Throwable t) {
t.printStackTrace();
}
});
4. Retrofit的原理
4.1 Retrofit的create方法
我们首先进入到create方法中:public在这里用到了Java的动态代理,可以看到我们在invoke中,我们进入到了loadServiceMethod中:T create(final Class service) {
// 在这里验证 接口是否合理
validateServiceInterface(service);
// 用到了Java的动态代理技术
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 {
// 如果对象是Object,不用管它
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 是否是Java8
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
ServiceMethod> loadServiceMethod(Method method) {在这里运用了缓存的技术,因为动态代理和创建一个ServiceMethod是比较耗时间的,而且一个api可能伴随着频繁的调用,所以在这里使用缓存技术可以有效的减少时间的消耗。当缓存中不存在的时候,就需要我们去创建一个新的ServiceMethod,于是调用 ServiceMethod.parseAnnotations(this, 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;
}
static让我们再进入到 HttpServiceMethod 中看看:ServiceMethod 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);
}
static先来看看 callAdapter 是怎么创建的?进入到 createCallAdapter 中:HttpServiceMethod parseAnnotations( {
Retrofit retrofit, Method method, RequestFactory requestFactory)
//....省略部分代码
CallAdaptercallAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
//.....
ConverterresponseConverter =
createResponseConverter(retrofit, method, responseType);
//. . . .
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
//....
}
private static再进入到 retrofit.callAdapter(returnType, annotations) :CallAdapter createCallAdapter( {
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations)
try {
//noinspection unchecked
return (CallAdapter) 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);
}
}
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {进入到nextCallAdapter() :
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,可以看到是从 callAdapterFactories 这个list集合中获取的,如果我们没有添加过CallAdapterFactory即:
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;
}
}
// ...... 省略部分代码
}
Retrofit retrofit = new Retrofit.Builder()那么会自动使用一个默认的CallAdapterFactory:DefaultCallAdapterFactory
.baseUrl("https://api.github.com/")
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
这个对象在build() 的时候会添加到集合中去:
public Retrofit build() {我们再转回来,最终会返回一个CallAdapted的实例,这个类的父类其实就是 HttpServiceMethod
// .....
//在这里添加 默认的 CallAdapterFactory
ListcallAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// ....
}
static final class CallAdapted就这样,在Retrofit的create的方法中loadServiceMethod 最终也是 返回了 一个 CallAdapted 实例,这个实例调用了 invoke方法,但是CallAdapted类没有invoke方法,那么追溯到它的父类 HttpServiceMethod :ReturnT > extends HttpServiceMethodReturnT >
@Override final @Nullable ReturnT invoke(Object[] args) {在这里创建了 一个 OkHttpCall ,然后调用了 adapt方法,CallAdapted类实现了这个抽象方法:
Callcall = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
@Override protected ReturnT adapt(Call这个 callAdapter 就是默认的DefaultCallAdapter :call, Object[] args) {
return callAdapter.adapt(call);
}
@Override public Call当 API调用的时候返回的Call对象就是这个了。在这里 executor 是不为null的,所以我们得到的 Call实例 是 ExecutorCallbackCall。因为在 Retrofit类的build() 的方法中:
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
Executor callbackExecutor = this.callbackExecutor;所以 拿到的是 platform 的 defaultCallbackExecutor(),
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
先看看 platform 的创建:
private static Platform findPlatform() {如果是 Android的话,则创建Andoid类:
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
return new Platform(true);
}
static final class Android extends Platform {所以 callbackExecutor是存在的,且数据会通过handler传递到主线程中。
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
4.2 Retrofit的网络请求
现在我们来看一下 Retrofit的网络请求:call.enqueue(new Callback首先我们知道了 这个call 是 ExecutorCallbackCall的 实例:让我们找到 enqueue 方法:>() {
@Override
public void onResponse(Call> call, Response
{> response)
// 数据返回成功
Log.i("zxy", "onResponse: success");
}
@Override
public void onFailure(Call> call, Throwable t)
{
// 数据返回失败
Log.i("zxy", "onFailure: fail");
}
});
@Override public void enqueue(final Callback已经知道delegate 就是 OKHttpCall,现在进入到OKHttpCall 中去找到 enqueue方法:callback) {
Objects.requireNonNull(callback, "callback == null");
// 这个 delegate 就是 OKHttpCall
delegate.enqueue(new Callback() {
@Override public void onResponse(Callcall, final Response {response)
// callbackExecutor 会通过handler 将数据回调到主线程
callbackExecutor.execute(() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override public void onFailure(Callcall, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override public void enqueue(final Callback其实可以看到最终的网络请求是由OkHttp3 做出的。我们看这个方法 createRawCall :callback) {
okhttp3.Call call;
Throwable failure;
// .....
try {
// 在这里创建 OkHttp3的Call
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
// .....
// 如果存在异常,就回调出去
if (failure != null) {
callback.onFailure(this, failure);
return;
}
// ......
// OkHttp 执行 请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Responseresponse;
try {
// 将 response 进行处理
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
}
}
});
}
private okhttp3.Call createRawCall() throws IOException {这里的callFactory 其实就是 OkHttp3的 OkHttpClient 的实例,在Retrofit的build()中:
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
okhttp3.Call.Factory callFactory = this.callFactory;在让我们看requestFactory,这个对象 在ServiceMethod中 就有生成:
if (callFactory == null) {
callFactory = new OkHttpClient();
}
static在requestFactory的create()方法中:ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
// .......
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
okhttp3.Request create(Object[] args) throws IOException {在create最后返回的是OkHttp3的Request对象。所以其实Retrofit中的网络请求是由OkHttp3来执行的。
//......
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
// .....
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
4.3 关于ConverterFactory
在最开始的实现Retrofit的对象的时候:.addConverterFactory(GsonConverterFactory.create())在HttPServiceMethod中的parseAnnotations:
// 这个就是 获得 responseConverter让我们继续进入到 createResponseConverter 中:
ConverterresponseConverter =
createResponseConverter(retrofit, method, responseType);
private static继续进入到retrofit#responseBodyConverter 中:Converter 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);
}
}
public拿GsonConverterFactory为例:Converter responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
publicConverter nextResponseBodyConverter( {
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations)
//......
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
// 在converter对象
Converterconverter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
//......
}
@Override那么它在哪里被使用呢?在call 执行enqueue 的时候,通过回调onResponse返回数据,在parseResponse()方法中会对数据进行处理:
public Converter?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
// 在这里就是返回了Converter对象
return new GsonResponseBodyConverter<>(gson, adapter);
}
Response在GsonResponseBodyConverter 的重写方法convert中就会对数据进行处理:parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
//......
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 这里的responseConverter 就是 GsonResponseBodyConverter
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
@Override public T convert(ResponseBody value) throws IOException {到这里,Retrofit的分析就结束了。
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
总结
Retrofit的代码简单优雅,值得我们去学习,学习源码有助于我们更好的思考。从源码中不仅仅是学习优秀的代码也是学习大神们的思想。这里有一些优秀的博文值得学习:- 从架构角度看Retrofit的作用、原理和启示
- Retrofit是如何工作的?
近期精彩内容推荐:
Python是一门神奇的语言! IntelliJ IDEA 的 2020 ,真的很牛皮! 删库跑路真的发生,技术总监干的! 2020年Java框架排行榜,谁居榜首?在看点这里好文分享给更多人↓↓
评论