Retrofit源码学习

2024-06-01 06:08
文章标签 源码 学习 retrofit

本文主要是介绍Retrofit源码学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

个人主页:https://chengang.plus/

文章将会同步到个人微信公众号:Android部落格

1 基本使用

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_retrofit);new Thread(new Runnable() {@Overridepublic void run() {try {Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).build();GithubService service = retrofit.create(GithubService.class);Call<ResponseBody> repos = service.listRepos("cg229836277");Response<ResponseBody> response = repos.execute();ResponseBody responseBody = response.body();String message = responseBody.string();MyLog.d(TAG, "message:" + message);Call<UserInfoBean> userRepos = service.getUserInfo("cg229836277");Response<UserInfoBean> userResponse = userRepos.execute();UserInfoBean userInfoBean = userResponse.body();String userName = userInfoBean.getName();MyLog.d(TAG, "userName:" + userName);} catch (Exception | Error e) {e.printStackTrace();}}}).start();
}

run方法中包裹的代码以空格为界,分为两部分,上半部分是返回的结果不解析,直接返回ResponseBody,拿到body string之后做其他处理;下半部分获取用户相关信息,由Gson解析序列化成UserInfoBean对象。

所有的接口定义在GithubService类中,如下:

public interface GithubService {@GET("users/{user}/repos")Call<ResponseBody> listRepos(@Path("user") String user);@GET("users/{user}")Call<UserInfoBean> getUserInfo(@Path("user") String user);
}

2 源码查看

2.1 Retrofit.Builder

首先需要构建Retrofit,通过Retrofit.Builder类构建。

看看构建方法里面的几个方法。

2.1.1 client
public Builder client(OkHttpClient client) {return callFactory(Objects.requireNonNull(client, "client == null"));
}public Builder callFactory(okhttp3.Call.Factory factory) {this.callFactory = Objects.requireNonNull(factory, "factory == null");return this;
}

这里将OkHttpClient设置为callFactory,因为OkHttpClient集成自Call.Factory,所以可以直接传递:

open class OkHttpClient internal constructor(builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
2.1.2 baseUrl

用于设置请求网址,比如https://api.github.com/是请求的基础url,后面还可以加很多请求query参数。

这个方法最终调用到:

public Builder baseUrl(HttpUrl baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");List<String> pathSegments = baseUrl.pathSegments();if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);}this.baseUrl = baseUrl;return this;
}

在调用之前还调用了HttpUrl的get方法,将传递进来的URL或String地址,转成HttpUrl类型:

private HttpUrl(Builder builder) {this.scheme = builder.scheme;this.username = percentDecode(builder.encodedUsername, false);this.password = percentDecode(builder.encodedPassword, false);this.host = builder.host;this.port = builder.effectivePort();this.pathSegments = percentDecode(builder.encodedPathSegments, false);this.queryNamesAndValues = builder.encodedQueryNamesAndValues != null? percentDecode(builder.encodedQueryNamesAndValues, true): null;this.fragment = builder.encodedFragment != null? percentDecode(builder.encodedFragment, false): null;this.url = builder.toString();
}

get方法将你传入的url先做规范化处理,比如url开始和结束位置有空格等其他非法字符等,处理完毕之后,接着获取请求方式,http或https,请求host,端口等信息。

2.1.3 addConverterFactory

这个方法中,可以添加请求数据或返回数据的序列化类。比如开头的实例中,需要将返回的用户信息序列化成UserInfoBean类,可以通过这个方法添加GsonConverterFactory对象。

2.1.4 addCallAdapterFactory

添加请求处理类,比如RxJavaCallAdapterFactory,可以通过将他的对象传递到这个方法,引入对RxJava的支持。

2.1.5 build
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);
}
  • baseUrl,上层不设置baseUrl,会直接报错;
  • callFactory,上层不设置,默认设置OkHttpClient,如果自己自定义的话,可以添加一些自定的interceptor,这个是okhttp的一大特色;
  • callAdapterFactories,将上层添加的请求工厂类添加进来,另外还有平台自己默认的一个请求工厂类,在Platform类中定义,如下:
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);return hasJava8Types? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory): singletonList(executorFactory);
}

这里hasJava8Types 在sdk版本大于等于24时,为true,这里将CompletableFutureCallAdapterFactory和DefaultCallAdapterFactory一起放到一个List中然后返回,这里DefaultCallAdapterFactory持有传递过来的callbackExecutor对象。

  • converterFactories

用于存放请求参数或结果参数的序列化工具,初始化如下:

// 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());//retrofit\src\main\java\retrofit2\Platform.java
List<? extends Converter.Factory> defaultConverterFactories() {return hasJava8Types ? singletonList(OptionalConverterFactory.INSTANCE) : emptyList();
}

OptionalConverterFactory只有在Android sdk 版本大于等于24才添加。

BuiltInConverters为默认添加的转换类。

总结

最终build方法返回一个Retrofit对象,封装了上述参数。

return new Retrofit(callFactory,baseUrl,unmodifiableList(converterFactories),unmodifiableList(callAdapterFactories),callbackExecutor,validateEagerly);

2.2 Retrofit.create

还是贴代码,然后分步骤分析:

public <T> T create(final Class<T> service) {validateServiceInterface(service);return (T)Proxy.newProxyInstance(...);
}

上边create方法的参数里面,Class对象service对应文章开头的GithubService类的对象。

2.2.1 validateServiceInterface

用于检查传递过来的形参service是否合法,第一,必须是interface类型;第二,interface类型的类,不能限定类型,比如GithubService。以上两种情况下只要不满足就会抛出异常。

private void validateServiceInterface(Class<?> service) {if (!service.isInterface()) {throw new IllegalArgumentException("API declarations must be interfaces.");}if (service.getTypeParameters().length != 0) {throw new IllegalArgumentException(message.toString());}
}

这个方法还涉及一个validateEagerly参数,在Retrofit.Builder中通过validateEagerly方法设置,如果设置为true之后,在这个方法中,就会接着解析interface里面的方法:

if (validateEagerly) {Platform platform = Platform.get();for (Method method : service.getDeclaredMethods()) {if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {loadServiceMethod(method);}}
}

isDefaultMethod表示当前方法是public且非abstract修饰的实例方法,也就是一个非static方法,有方法体,在interface里面定义。其实说的是java 8的新特性,在interface中,可以添加default修饰符到一个方法,这个方法可以有实现,可以避免当在interface中添加一个方法,所有实现都必须改动的问题。

A default method is a public non-abstract instance method, that is, a non-static method with a body, declared in an interface type.

validateEagerly为true时,会获取到service interface下所有定义的方法,并判断所有方法的类型,如果满足非static并且是default方法,就会调用loadServiceMethod方法,这个方法下一节分析。

2.3 调用interface中的方法

以文章开头demo中GithubService中的方法为例,通过GithubService service = retrofit.create(GithubService.class);获取了GithubService对象,接下来调用里面定义的API方法,具体调用在Retrofit.create方法中定义的内部类中实现:

return (T)Proxy.newProxyInstance(service.getClassLoader(),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);}});

在InvocationHandler类中,调用最后在invoke方法里面:

  • proxy,Retrofit的代理对象;
  • method,GithubService中定义的方法;
  • args,方法中定义的参数,比如Call<ResponseBody> listRepos(@Path("user") String user);的参数就是user。

2.4 ServiceMethod和HttpServiceMethod

接下来判断是否是default修饰的方法,如果是,就直接调用,否则通过loadServiceMethod方法调用。

ServiceMethod

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);Type returnType = method.getGenericReturnType();if (Utils.hasUnresolvableType(returnType)) {}return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

通过这个方法可以拆分出很多细节,包括注解解析,返回类型解析等。最终这些属性被封装到ServiceMethod类中。

//Retrofit
ServiceMethod<?> loadServiceMethod(Method method) {ServiceMethod result = ServiceMethod.parseAnnotations(this, method);
}
//ServiceMethod
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
//RequestFactory
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {return new Builder(retrofit, method).build();
}RequestFactory build() {for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}int parameterCount = parameterAnnotationsArray.length;parameterHandlers = new ParameterHandler<?>[parameterCount];for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {parameterHandlers[p] =parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);}return new RequestFactory(this);
}

上边的代码引申出了RequestFactory,这个类主要处理请求相关的参数。

2.4.1 RequestFactory
  • parseAnnotations

方法中通过建造者模式,构建了请求相关的诸多参数,这里只分析其中比较核心的参数。

  • parseMethodAnnotation

通过方法可以知道,这个方法主要解析方法的注解:

private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof DELETE) {parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);} else if (annotation instanceof GET) {parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);} else if (annotation instanceof HEAD) {parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);} else if (annotation instanceof PATCH) {parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);} else if (annotation instanceof POST) {parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);} else if (annotation instanceof PUT) {parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);} else if (annotation instanceof OPTIONS) {parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);} else if (annotation instanceof HTTP) {HTTP http = (HTTP) annotation;parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());} else if (annotation instanceof retrofit2.http.Headers) {String[] headersToParse = ((retrofit2.http.Headers) annotation).value();if (headersToParse.length == 0) {throw methodError(method, "@Headers annotation is empty.");}headers = parseHeaders(headersToParse);} else if (annotation instanceof Multipart) {if (isFormEncoded) {throw methodError(method, "Only one encoding annotation is allowed.");}isMultipart = true;} else if (annotation instanceof FormUrlEncoded) {if (isMultipart) {throw methodError(method, "Only one encoding annotation is allowed.");}isFormEncoded = true;}
}

请求方法判断

if-else判断,从DELETE到OPTIONS都属于http的请求方法,参见:https://www.runoob.com/http/http-methods.html。

请求方法注解参数

@GET("users/{user}/repos")

以上述GET请求方法为例,parseHttpMethodAndPath方法解析出了users/{user}/repos这个地址,以及地址中的user参数。

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {this.httpMethod = httpMethod;this.hasBody = hasBody;this.relativeUrl = value;this.relativeUrlParamNames = parsePathParameters(value);
}

relativeUrl对应地址,relativeUrlParamNames对应地址中的动态参数。

注解以HTTP开头

表示可以自定义请求,示例如下:

@HTTP(method = "GET", path = "users/{user}", hasBody = false)
Call<UserInfoBean> getUserInfo1(@Path("user") String user);

注解以Headers开头

在http请求中添加请求头,如果一个项目中多个请求API都有相同的header字段,比如每个请求头中都有设备型号字段,设备的Android版本字段等,可以统一在OKHttpClient中添加Interceptor,而Interceptor中通过添加Request.Builder设置。这个OKHttpClient对象通过Retrofit.Builder中的client方法设置:

public Builder client(OkHttpClient client) {}

注解包含Multipart

常见的 POST 数据提交的方式。使用表单上传文件时,必须让 表单的 enctype 等于 multipart/form-data。

请求头必须包含一个特殊的头信息:Content-Type,且其值必须是multipart/form-data,同时还要规定一个内容分隔符,用于分隔请求体中的多个POST内容。具体的头信息如下:
Content-Type: multipart/form-data; boundary=${bound}

https://imququ.com/post/four-ways-to-post-data-in-http.html

示例如下:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/pngPNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

主要用于上传文件。

注解包含FormUrlEncoded

其实是Content-Type:application/x-www-form-urlencoded,是post提交数据的一种方式,请求参数采用类似get的参数拼接方式。

application/x-www-form-urlencoded

  • post的默认请求

  • 需要把对象参数序列化为字符串参数

  • 参数采用类似get的参数拼接方式

  • 使用URIencode转码方式,转码会增加体积,适合短字节

  • 请求参数放在请求体里

  • 不在地址栏显示参数,安全性高

multipart/form-data

  • 不转码,适合传输长字节(如文件)

  • 请求参数放在请求体里

  • 不在地址栏显示参数,安全性高

  • parseParameter

解析注解地址中的参数。

private @Nullable ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {ParameterHandler<?> result = null;if (annotations != null) {for (Annotation annotation : annotations) {ParameterHandler<?> annotationAction =parseParameterAnnotation(p, parameterType, annotations, annotation);result = annotationAction;}}return result;
}private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) {if (annotation instanceof Url) {return new ParameterHandler.RelativeUrl(method, p);} else if (annotation instanceof Path) {Converter<?, String> converter = retrofit.stringConverter(type, annotations);return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());} else if (annotation instanceof Query) {Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);return new ParameterHandler.Query<>(name, converter, encoded).iterable();}....
}

这里根据注解不同类型,返回不同类型的ParameterHandler,这个类的作用会在后面生成Request的时候,将API传递的参数值args替换到注解的地址或请求参数中。

例如ParameterHandler.Path会将注解中的{user}替换为cg229836277。

2.4.2 HttpServiceMethod.parseAnnotations

ServiceMethod的parseAnnotations方法中,最后调用了HttpServiceMethod.parseAnnotations方法返回,同时也作为loadServiceMethod的结果返回。同时也是demo中GithubService调用API返回的结果,是Call类型。

  • parseAnnotations
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {Type adapterType = method.getGenericReturnType();CallAdapter<ResponseT, ReturnT> callAdapter =createCallAdapter(retrofit, method, adapterType, annotations);Type responseType = callAdapter.responseType();Converter<ResponseBody, ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType);okhttp3.Call.Factory callFactory = retrofit.callFactory;return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}

最中返回一个CallAdapted的对象。

  • createCallAdapter

创建了请求CallAdapter,从Retrofit的callAdapterFactories列表中取:

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

Retrofit

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

Retrofit的callAdapterFactories中最开始添加的child是:

Platform

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);return hasJava8Types? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory): singletonList(executorFactory);
}

CompletableFutureCallAdapterFactory和DefaultCallAdapterFactory被添加进来。

根据返回的泛型数据类型以及注解,最终返回的是DefaultCallAdapterFactory。然后调用get方法,返回CallAdapter的对象。

public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit){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);}};
}

这里的executor就是通过Retrofit.Builder中的callbackExecutor方法设置的。

  • createResponseConverter

HttpServiceMethod

private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {return retrofit.responseBodyConverter(responseType, annotations);
}

同样的从Retrofit.Builder的build方法中初始化的几个Converter中确定:

Retrofit.Builder

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

Retrofit

public <T> Converter<ResponseBody, T> 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<ResponseBody, ?> converter =converterFactories.get(i).responseBodyConverter(type, annotations, this);if (converter != null) {//noinspection uncheckedreturn (Converter<ResponseBody, T>) converter;}}
}

这里选择BuiltInConverters,调用其responseBodyConverter方法,实际返回的是BufferingResponseBodyConverter。

如果我们需要序列化的话,选择的就是在Retrofit构建时通过addConverterFactory传递进来的GsonConverterFactory,这里实际返回的是GsonResponseBodyConverter。

  • callFactory

在Retrofit.Builder的build方法中,callFactory不设置的话,默认新建了一个OkHttpClient。

总结

HttpServiceMethod的parseAnnotations方法最后,将上述几个参数封装到CallAdapted返回。

2.4.3 HttpServiceMethod.invoke

这个方法中先将上一节生成的几个对象封装到Call,然后调用CallAdapted的adapt方法返回。

HttpServiceMethod

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

args中就是调用API方法传递过来的。

CallAdapted

@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {return callAdapter.adapt(call);
}

上一节分析过,callAdapter实际是DefaultCallAdapterFactory中get方法返回的CallAdapter,这里调用adapt方法返回:

@Override
public Call<Object> adapt(Call<Object> call) {return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}

分两种情况,依据是是否通过Retrofit.Bulider的callbackExecutor设置executor:

  • 不设置的话,为空,返回OkHttpCall;
  • 设置之后,返回ExecutorCallbackCall,同时封装了executor和OkHttpCall。

ExecutorCallbackCall

ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {this.callbackExecutor = callbackExecutor;this.delegate = delegate;
}

这里的callbackExecutor就是Retrofit构建的时候传入的线程池对象。在下一步执行请求的时候可能会用到。

2.5 Call.execute

此处会在上一步返回的ExecutorCallbackCall中执行:

ExecutorCallbackCall

public Response<T> execute() throws IOException {return delegate.execute();
}

delegate指向OkHttpCall,看看他的execute方法:

OkHttpCall

@Override
public Response<T> execute() throws IOException {okhttp3.Call call;synchronized (this) {if (executed) throw new IllegalStateException("Already executed.");executed = true;call = getRawCall();}if (canceled) {call.cancel();}return parseResponse(call.execute());
}private okhttp3.Call getRawCall() throws IOException {return rawCall = createRawCall();
}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;
}
  • RequestFactory.create

RequestFactory

okhttp3.Request create(Object[] args) throws IOException {ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;RequestBuilder requestBuilder =new RequestBuilder(httpMethod,baseUrl,relativeUrl,headers,contentType,hasBody,isFormEncoded,isMultipart);List<Object> argumentList = new ArrayList<>(argumentCount);for (int p = 0; p < argumentCount; p++) {argumentList.add(args[p]);handlers[p].apply(requestBuilder, args[p]);}return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}

通过API上边的注解获取了请求相关的属性信息,这里返回okhttp3.Request对象。

方法中的for循环,根据API调用时传递过来的参数,透过ParameterHandler对应到注解变量中,示例如下:

@GET("users/{user}")
Call<UserInfoBean> getUserInfo(@Path("user") String user);

Path类型的注解最终调用到ParameterHandler.Path类中的apply方法,最终拼接的逻辑在RequestBuilder的addPathParam方法中:

RequestBuilder

void addPathParam(String name, String value, boolean encoded) {String replacement = canonicalizeForPath(value, encoded);String newRelativeUrl = relativeUrl.replace("{" + name + "}", replacement);if (PATH_TRAVERSAL.matcher(newRelativeUrl).matches()) {throw new IllegalArgumentException("@Path parameters shouldn't perform path traversal ('.' or '..'): " + value);}relativeUrl = newRelativeUrl;
}
  • 生成okhttp Request

首先通过RequestBuilder的get方法,将baseUrl和relativeUrl拼接起来,作为请求Url;

然后通过不同的contentType将对应的参数填充到RequestBody;

再将url,header,method,body封装到RequestBuilder返回;

最后调用RequestBuilder的build方法,将上述信息封装到okhttp3.Request中。

  • newCall

callFactory对应OkHttpClient,这里调用newCall之后,返回okhttp3.Call,然后调用execute方法返回结果。

2.6 结果解析

从OkHttpCall的execute方法最后一行开始:

@Override
public Response<T> execute() throws IOException {return parseResponse(call.execute());
}

parseResponse方法做具体的解析工作:

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();rawResponse =rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();int code = rawResponse.code();...ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);T body = responseConverter.convert(catchingBody);return Response.success(body, rawResponse);
}
  • 第一步获取Response.body,然后将Response中的code,headers等重新封装到Response中。
  • code小于200或大于300统一处理为报错;code等于204或205处理为成功,但是没有内容。
  • 处理成功的内容,需要根据最初Retrofit.Builder构建的时候传递的Converter将结果中的body序列化成API返回Call泛型限定的类型。

responseConverter通过构建OkHttpCall时传递过来。根据前面的分析,HttpServiceMethod.invoke构建了OkHttpCall,传递过来的responseConverter实际是BufferingResponseBodyConverter或自定义的转换类型。

针对返回Response类型的数据,使用BufferingResponseBodyConverter,将body封装到返回:

BufferingResponseBodyConverter.convert

Utils.buffer

static ResponseBody buffer(final ResponseBody body) throws IOException {Buffer buffer = new Buffer();body.source().readAll(buffer);return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}

针对返回Response类型的数据,使用GsonResponseBodyConverter,将body序列化成T返回:

public T convert(ResponseBody value) throws IOException {JsonReader jsonReader = gson.newJsonReader(value.charStream());try {T result = adapter.read(jsonReader);return result;} finally {value.close();}
}

最后通过Response.success方法将返回的原始okhttp3.Response及body返回给调用者。

2.6.2 enqueue方法调用

另外根据OkHttpCall类提供的enqueue方法,可以换一种请求方式:

Call<UserInfoBean> userRepos = service.getUserInfo1("cg229836277");
userRepos.enqueue(new Callback<UserInfoBean>() {@Overridepublic void onResponse(Call<UserInfoBean> call, Response<UserInfoBean> response) {UserInfoBean userInfoBean = response.body();String userName = userInfoBean.getName();Log.d(TAG, "userName:" + userName);}@Overridepublic void onFailure(Call<UserInfoBean> call, Throwable t) {Log.d(TAG, "userName error:" + t);}
});

在Retrofit构建时调用callbackExecutor传递自定义的工作线程,可以直接在UI线程中调用,因为okhttp的enqueue方法会在自定义的工作线程中请求,而execute方法则不会。如果设置了线程池,会在DefaultCallAdapterFactory.ExecutorCallbackCall中调用:

@Override
public 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.callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {callback.onResponse(ExecutorCallbackCall.this, response);}});}@Overridepublic void onFailure(Call<T> call, final Throwable t) {callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));}});
}

3 总结

Retrofit总体看来就是使用了注解,简化了各种请求参数的填写。底层请求还是用的OkHttp。

另外上层提供了请求和结果处理的接口,使得这部分处理具有很大的灵活性,比如请求的时候可以通过addCallAdapterFactory方法添加RxJava。

另外需要注意的是,源码里面选择CallAdapter和Converter的方式,核心是下边两行代码:

//获取请求
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
//获取转换
Converter<ResponseBody, ?> converter =converterFactories.get(i).responseBodyConverter(type, annotations, this);

get方法在各自的转换类中实现,如果与方法的返回类型,及类型的泛型向匹配就返回对应的请求或转换类。

这篇关于Retrofit源码学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1020188

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识