簡介
剛接觸Retrofit
的時候,就寫了一篇簡單的使用介紹:Retrofit 2.0基本使用方法,算是對Retrofit的基礎入門。也算是接觸Retrofit
一段時間了,現在差不多可以對源碼層進行解析,最起碼,理解原理后可以使得我們使用起來更加得心應手 _。
網絡請求使用基本方法
參考官網:
Introduction
Retrofit turns your HTTP API into a Java interface.
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
The Retrofit class generates an implementation of the GitHubService interface.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.
Call<List<Repo>> repos = service.listRepos("octocat");
//synchronous request
repos.execute();
//asynchronous request
repos.enqueue(new Callback<ResponseBody>() {/***/});
Use annotations to describe the HTTP request:
URL parameter replacement and query parameter support
Object conversion to request body (e.g., JSON, protocol buffers)
Multipart request body and file upload
源碼解析: retrofit:2.3.0
從上一節的使用Retrofit
進行網絡請求中,我們可以看到,請求過程主要分為以下幾步:
- 創建一個接口進行HTTP請求描述;
- 使用
Retrofit.Builder
構建模式構造出一個Retrofit
實例; - 調用
retrofit.create()
方法獲取請求接口實例; - 由請求接口實例獲取到
Call
對象; - 進行網絡請求(同步/異步)
接下來,我們就按照以上正常的網絡請求順序來對Retrofit
源碼進行解析。
-
創建一個接口進行HTTP請求描述
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
這里主要做的就是采用注解的方式進行HTTP描述,后面在第4步由請求接口實例獲取到Call
對象時進行反射提取注解內容進行HTTP請求構造(如果開啟了預先加載解析(validateEagerly=true
),那么在第3步調用retrofit.create()
方法獲取請求接口實例的時候就會進行注解解析),具體解析方法參考后續分析。
-
使用Retrofit.Builder構建模式構造出一個Retrofit實例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
那我們就先來看下Retrofit.Builder
部分源碼:
/**
* Build a new {@link Retrofit}.
* <p>
* Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods
* are optional.
*/
public static final class Builder {
private final Platform platform;
//callFactory通過newCall(Request request)方法,返回一個okhttp3.Call對象,以便讓我們進行實際的HTTP請求
//也就是說callFactory是我們用來生成一個客戶端HTTP請求工廠實例
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
//converterFactories生產Converter<F, T>,用于將HTTP返回結果F類型轉換為T類型,或將HTTP請求類型F轉換為T。
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//adapterFactories生產 CallAdapter<R, T>,用于將retrofit2.Call<R>網絡請求類型轉換為T類型:T adapt(Call<R> var1);
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private @Nullable
Executor callbackExecutor;
private boolean validateEagerly;
···
···
···
}
從Retrofit.Builder
的注釋中,我們可以看到,在調用Retrofit.Builder.build()
之前,除了baseUrl()
是必須配置的以外,其他的內容都是可選配置。
這里要對兩個類型做下講解,因為筆者在剛分析Retrofit
源碼時,被這兩個類型的概念弄得頭暈眼脹,好在一頓分析后,終于有了一點眉目,這兩個類型就是:Converter<F, T>
和CallAdapter<R, T>
。
Converter<F, T>
:數據轉換器,用來將HTTP請求返回結果由F類型轉換為T類型,或者將HTTP請求類型F轉換為T
/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter<F, T> {
T convert(F value) throws IOException;
···
···
···
}
舉例:
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
上面配置了ConverterFactory
為GsonConverterFactory
,那么當HTTP請求結果返回時,就會由GsonConverterFactory
產生的Converter
,假設為Converter<ResponseBody, List<Repo>>
,該Converter
就會將HTTP返回結果ResponseBody
轉換為 List<Repo>
。
而若是將對象轉換為數據,那么假設類型為:Converter< List<Repo>, RequestBody>
,該Converter
在構建請求體時,會將List<Repo>
轉換為RequestBody
對象。
CallAdapter<R, T>
:請求適配器,用于將retrofit2.Call<R>
網絡請求類型轉換為T類型
/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is
* {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit}
* instance.
*/
public interface CallAdapter<R, T> {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type
* is used to prepare the {@code call} passed to {@code #adapt}.
* <p>
* Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();
/**
* Returns an instance of {@code T} which delegates to {@code call}.
* <p>
* For example, given an instance for a hypothetical utility, {@code Async}, this instance would
* return a new {@code Async<R>} which invoked {@code call} when run.
* <pre><code>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
* return Async.create(new Callable<Response<R>>() {
* @Override
* public Response<R> call() throws Exception {
* return call.execute();
* }
* });
* }
* </code></pre>
*/
T adapt(Call<R> call);
/**
* Creates {@link CallAdapter} instances based on the return type of {@linkplain
* Retrofit#create(Class) the service interface} methods.
*/
···
···
···
}
舉例:
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
上面配置了CallAdapterFactory
為RxJava2CallAdapterFactory
,這里的作用就是將Retrofit2.Call<T>
對象轉換為Observable<T>
類型,所以如果配置了RxJava2CallAdapterFactory
,那么接口方法聲明應該改為如下形式:
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
其實這個addCallAdapterFactory
實現原理是挺簡單的,因為Retrofit
里面維護了CallAdapter.Factory
一個數組,在使用Builder
配置的時候,所有配置的CallAdapter.Factory
最后都會保存到Retrofit
那個數組中,后面在進行轉換是,Retrofit
會根據接口方法返回結果類型(此處為:Observable<List<Repo>>)
,遍歷CallAdapter.Factory
數組,找到一個能處理該返回類型的CallAdapter
后,就不再遍歷。更多具體的解析方法請參考后續整體流程的介紹。
上面講了那么多的東西,可是還是沒有講到Retrofit
實例的創建,別著急,在查看Retrofit.Builder.build()
方法前,我們還要看下Builder
的構造函數:
Builder(Platform platform) {
this.platform = platform;
// 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());
}
public Builder() {
this(Platform.get());
}
當我們調用:
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
就會走入:Builder()--> Builder(Platform platform)
然后我們看到,在Builder(Platform platform)
構造函數里面,會往converterFactories
里面添加進一個BuiltInConverters
對象,所以默認的ConverterFactory
就是BuiltInConverters
。前面說過ConverterFactory
主要是用來將HTTP返回結果進行類型轉換或者將HTTP請求體進行類型轉換,然后我們看下BuiltInConverters
是怎樣的轉換方式:
final class BuiltInConverters extends Converter.Factory {
//返回結果轉換
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
//如果annotations是Streaming類型
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
//請求轉換
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
@Override public Void convert(ResponseBody value) throws IOException {
value.close();
return null;
}
}
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override public RequestBody convert(RequestBody value) throws IOException {
return value;
}
}
static final class StreamingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
return value;
}
}
static final class BufferingResponseBodyConverter
implements Converter<ResponseBody, ResponseBody> {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
}
返回結果轉換的時候,有3種情況:
- 如果返回類型是
ResponseBody
類型,那么可能返回的是:StreamingResponseBodyConverter.INSTANCE
或者BufferingResponseBodyConverter.INSTANCE
,再跟蹤進去這兩個類里面的convert
函數:
@Override public ResponseBody convert(ResponseBody value){···}
發現傳入的是ResponseBody
,返回的也是ResponseBody
(BufferingResponseBodyConverter
里面有進行特殊處理,主要是為了去除future I/O),所以我們可以認為BuiltInConverters
對HTTP返回結果沒有進行轉換處理。
- 如果返回類型是
Void
類型,那么最終就將ResponseBody
資源關閉后,直接返回null
。 - 如果返回類型不是
ResponseBody
和Void
類型,直接返回null
。
同理,我們來看下請求體轉換:
//請求轉換
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
@Override public RequestBody convert(RequestBody value) throws IOException {
return value;
}
}
可以看到,如果是RequestBody
類型,那就不轉換,如果不是RequestBody
類型,直接返回null
。
綜上所述:BuiltInConverters
只能響應ResponseBody
和RequestBody
,但是并不進行任何轉換.對于其他類型,統統返回null。
到這里,終于可以走進Retrofit.Builder.build()
函數,一窺究竟:
/**
* Create the {@link Retrofit} instance using the configured values.
* <p>
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
*/
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//callFactory默認為OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//默認的callbackExecutor為Platform.Android.MainThreadExecutor
//MainThreadExecutor繼承Executor,并復寫execute(Runnable r),
// execute內部直接通過主線程Handler.post(r),即r.run發生在主線程
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//defaultCallAdapterFactory是ExecutorCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//BuiltInConverters在Retrofit.Builder(Platform)構造時,已被傳入
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
build
函數一進去,就看到:
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
這說明baseUrl
是一定要進行配置的,否則程序就會拋出異常,這跟我們上面講到的一致。
接著往下看:
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//callFactory默認為OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//默認的callbackExecutor為Platform.Android.MainThreadExecutor
//MainThreadExecutor繼承Executor,并復寫execute(Runnable r),
// execute內部直接通過主線程Handler.post(r),即r.run發生在主線程
callbackExecutor = platform.defaultCallbackExecutor();
}
這里可以看到,如果沒有配置okhttp3.Call.Factory
,那么就會使用默認的HTTP工廠類:OkHttpClient
,用于客戶端程序創建okhttp3.Call
對象,以進行實際的HTTP網絡請求。
如果沒有線程調度器callbackExecutor
,那么就會使用默認的線程調度器:Platform.Android.MainThreadExecutor
:
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
從源碼可以看出,默認的線程調度器是主線程調度器。
接下來再看:
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//defaultCallAdapterFactory是ExecutorCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
可以看到,這里為adapterFactories
增加了一個CallAdapterFactory
:
//Platform.java
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
//ExecutorCallAdapterFactory.java
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements retrofit2.Call<T> {
final Executor callbackExecutor;
//HTTP請求委托類
final retrofit2.Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
//異步請求
@Override
public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
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(new Runnable() {
@Override
public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
//同步請求
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
···
···
···
}
在Android平臺上,callbackExecutor
默認不為null,所以defaultCallAdapterFactory
返回的是ExecutorCallAdapterFactory
。從ExecutorCallAdapterFactory
的get
函數,可以看到,ExecutorCallAdapterFactory
只會響應返回類型為Call
的函數聲明(所以,如果我們沒有配置addCallAdapterFactory()
,那么我們接口函數聲明的返回類型必須為Call<?>
),響應處理的最終結果就是返回一個CallAdapter
,這個CallAdapter
的adapt()
函數會傳入一個HTTP請求委托類,然后返回一個HTTP請求代理類:ExecutorCallbackCall<T> implements retrofit2.Call<T>
,這個代理類代理了委托類的異步HTTP網絡請求,并將返回結果通過線程調度器將回調監聽函數分發到具體線程上執行(默認線程調度器是主線程調度)。
講到這里,Retrofit
實例的配置創建就算是完成了。下面這個圖展示了Retrofit.Builder
提供的配置選項:
-
調用retrofit.create()方法獲取請求接口實例
GitHubService service = retrofit.create(GitHubService.class);
那我們接下來就看一下create()
的源碼:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
//1.是否是接口
//2.不能繼承其他接口
Utils.validateServiceInterface(service);
//預先加載解析注解:loadServiceMethod
//默認false,即調用接口方法后,才進行解析
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public 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);
}
//java8平臺使用
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
這里我們可以看到,create
方法返回的是一個 (T) Proxy.newProxyInstance()
方法產生的一個動態代理對象(如果不清楚動態代理,可以看下我之前寫的文章:Java代理模式,里面對java的動態代理有詳細講解)。使用該動態代理對象進行方法調用后,會自動被InvocationHandler
攔截,最終進入InvocationHandler
的invoke
函數里面。
-
由請求接口實例獲取到Call對象
Call<List<Repo>> repos = service.listRepos("octocat")
從上面create
的分析中,我們知道,此處的service
是一個動態代理類對象,所以,在調用方法時,會被InvocationHandler
的invoke
方法攔截,所以調用:service.listRepos("octocat")
就會進入InvocationHandler.invoke()
中,查看下invoke
函數,最主要的操作就是如下3句話:
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
ServiceMethod
在Retrofit
中是一個很重要的類,主要做的就是對接口方法注解進行解析,最終生成一個Request
。
那我們先來看下loadServiceMethod()
源碼:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
serviceMethodCache
是一個緩存容器,是對接口方法的解析緩存。
//class Retrofit
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
從loadServiceMethod()
中可以看到,ServiceMethod
的實例也是通過builder
模式進行構建的,構建過程需傳入Retrofit
對象和Method
對象。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//取得接口方法的注解
this.methodAnnotations = method.getAnnotations();
//返回接口方法參數類型
this.parameterTypes = method.getGenericParameterTypes();
//返回接口方法各個參數注解
//按參數聲明順序排列,每個參數可能有多個注解,故二維數組
//parameterAnnotationsArray[0][i]:第一個參數第i個注解
//parameterAnnotationsArray[1][j]:第二個參數第j個注解
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
//CallAdapter<T, R> callAdapter;適配Call的響應類型,將默認響應類型R轉換為類型T
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//Converter<ResponseBody, T> responseConverter;HTTP交互中,轉換對象為數據 或 從數據轉換為對象
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
···
···
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
···
···
return new ServiceMethod<>(this);
}
在ServiceMethod.Builder.build()
源碼中可以看到:
callAdapter = createCallAdapter();
首先創建一個callAdapter
,具體創建過程如下:
private CallAdapter<T, R> createCallAdapter() {
//接口方法return類型
Type returnType = method.getGenericReturnType();
···
···
Annotation[] annotations = method.getAnnotations();
//noinspection unchecked
···
···
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
}
可以看到,其最終調用到的是retrofit.callAdapter()
:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
// final List<CallAdapter.Factory> adapterFactories;
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//throw exception
···
···
}
可以看到,createCallAdapter()
就是從Retrofit
的List<CallAdapter.Factory> adapterFactories
數組中,遍歷找到一個可以處理該接口方法返回類型和注解的CallAdapter<?, ?>
。那根據我們之前的分析,如果我們沒有進行CallAdapter
的配置,那么默認的CallAdapter
就是ExecutorCallAdapterFactory.get(Call.class,xxx,retrofit)
;
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if(getRawType(returnType) != Call.class) {
return null;
} else {
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
public Type responseType() {
return responseType;
}
public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
}
};
}
}
可以看到,默認的CallAdapter.Factory
只會響應接口方法返回類型為Call
,所以遍歷adapterFactories
的時候,如果接口方法返回類型不是Call
,那么ExecutorCallAdapterFactory.get()
自然返回的就是null
,然后就會繼續找下一個CallAdapterFactory
,繼續嘗試,直到找到能處理該接口方法返回類型的CallAdapterFactory
,由其返回一個CallAdapter
。
上面的流程可以這樣想(較為生動):
createCallAdapter
說:retrofit
,給我一個能處理我這個接口方法返回類型(假設為Observable<T>
)的CallAdapter
。
retrofit
接收到請求后,就會從自己的adapterFactories
倉庫中一個一個的進行詢問:
首先找到默認的CallAdapter.Factory
:ExecutorCallAdapterFactory
,然后說:ExecutorCallAdapterFactory
啊,你能處理Observable<T>
這個返回類型嗎?
ExecutorCallAdapterFactory
一看,說:retrofit
啊,你給我的返回類型不是Call
類型,我沒辦法處理,你找下一位CallAdapter.Factory
仁兄吧。
既然默認的ExecutorCallAdapterFactory
沒辦法處理這個接口方法返回類型,那retrofit
就只能繼續問下一位CallAdapter.Factory
啦,假設下一位是RxJava2CallAdapterFactory
,然后,retrofit
開始發問,說:RxJava2CallAdapterFactory
仁兄呀,你能處理Observable<T>
這個返回類型嗎?
RxJava2CallAdapterFactory
一看,說:retrofit
兄啊,你這個Observable<T>
我拿手呀,隨隨便便進行處理,處理的結果拿到了這個CallAdapter
,你趕緊拿著給createCallAdapter
交差吧。
retrofit
一聽,太高興了,說到:RxJava2CallAdapterFactory
兄啊,您真牛逼,謝謝您了,好的好的,我趕緊拿著您給的CallAdapter
給createCallAdapter
交差,那邊催的緊呢。
于是,retrofit
高高興興地就往createCallAdapter
那邊趕了,adapterFactories
后面還沒問到的兄弟就不管了,沒辦法,哥(retrofit
)時間緊,沒有那么多時間去一 一問候兄弟們,望兄弟們見諒 _。
我們接著看ServiceMethod.Builder.build()
方法,可以看到,createCallAdapter
后,又createResponseConverter
了:
//Converter<ResponseBody, T> responseConverter;HTTP交互中,轉換對象為數據 或 從數據轉換為對象
responseConverter = createResponseConverter();
responseConverter
是Converter<ResponseBody, T>
類型,其實我們一看到這個,就應該大概知道是怎么做了,肯定又是跟retrofit
請求,retrofit
又從倉庫中進行查找,只是這回是從List<Converter.Factory> converterFactories
中查找,直到找到一個能處理這種responseType
的Converter.Factory
,由其返回一個Converter
。讓我們看下源碼是不是這樣的:
//ServiceMethod.java
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
//Retrofit.java
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
/**
* Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available
* {@linkplain #converterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no converter available for {@code type}.
*/
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
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 unchecked
return (Converter<ResponseBody, T>) converter;
}
}
//throw exception
···
···
···
}
可以看到,跟我們上面所說的過程是一樣的。
還記得嗎,有一個默認的retrofit2.Converter.Factory
是:BuiltInConverters
。那從BuiltInConverters
得到的Converter<ResponseBody, T>
是什么呢,根據我們之前的分析:
- 如果
responseType
是ResponseBody
類型,那么返回的還是ResponseBody
(BufferingResponseBodyConverter
有經過一些處理); - 如果
responseType
是Void
類型,那么釋放ResponseBody
資源,然后返回null; - 其他
responseType
類型,直接返回null
。
所以,如果我們沒有配置addConverterFactory
,那么接口返回類型應該聲明為Call<ResponseBody>
或者Call<Void>
這類型的,這樣,默認的retrofit2.Converter.Factory
才能進行處理。
接著看Retrofit.Builder.build()
方法,可以看到:
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
這個是一個很重要的操作,就是對接口方法進行解析,追蹤進去再看下解析源碼:
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);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} 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("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
可以看到里面對很多方法都進行了解析,這里,我們就只拿GET
方法解析源碼來分析下解析流程,其余方法解析都是類似的:
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
···
···
···
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
按照官網那個例子,那么:this.relativeUrl = value = "users/{user}/repos"
,在parseHttpMethodAndPath
最后,調用了 parsePathParameters(value)
:
/**
* Gets the set of unique path parameters used in the given URI. If a parameter is used twice
* in the URI, it will only show up once in the set.
*/
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
這里采用正則表達式取出形如"{*}"這種結構的內容,保留在全局Set<String> relativeUrlParamNames
集合里面。
像官網這個例子,當程序來到parsePathParameters("users/{user}/repos")
的時候,正則表達式就獲得了user
這個字符串,并存儲到全局relativeUrlParamNames
里面。這樣,接口方法的可變字符串就被記錄了起來,后續只要獲取到參數注解內容的名字是一樣的(eg:@Path("user") String user
,參數注解內容是"user“
),將參數轉換(Converter
,默認為StringConverter
,轉換就是直接調用參數對象的toString()
方法轉成字符串)放入方法路徑可成為一個真正的relativeUrl
。
以上就是方法注解的解析過程。
但是接口方法參數的注解還沒進行解析,那我們就繼續往下看ServiceMethod.Builder.build()
方法,可以看到:
//有多少個參數帶注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
//參數類型
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
//參數對應的注解數組
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
//根據參數類型和對應注解集合進行解析,封裝到parameterHandlers中
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
參數注解解析過程的最后調用了:parseParameter
,這個方法會根據傳入的參數類型和對應注解集合進行解析,封裝成為ParameterHandler
,將每個參數的注解解析最后都存入到parameterHandlers
數組中,所以parameterHandlers[0]
就是第一個帶注解的參數的解析內容,parameterHandlers[1]
就是第二個帶注解的參數的解析內容····:
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
return result;
}
可以看到parseParameter
主要做的就是遍歷參數的所有注解,一個一個進行注解解析:parseParameterAnnotation
,這個方法內部代碼特別長,因為有很多種注解需要分析,在這里,我們就只抽取出@Path
的注解解析部分內容:
//參數注解解析
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
····
····
····
else if (annotation instanceof Path) {
if (gotQuery) {
throw parameterError(p, "A @Path parameter must not come after a @Query.");
}
if (gotUrl) {
throw parameterError(p, "@Path parameters may not be used with @Url.");
}
if (relativeUrl == null) {
throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod);
}
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
/**
* 有效性檢驗:
* 1.命名規范:必須符合正則:[a-zA-Z][a-zA-Z0-9_-]*
* 2.注解value必須存在relativeUrlParamNames方法變量,對應起來
*/
validatePathName(p, name);
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(name, converter, path.encoded());
}
···
···
···
}
這里對@Path
的解析最主要的就是獲取一個Converter<?, String>
,獲取是通過retrofit.stringConverter()
:
/**
* Returns a {@link Converter} for {@code type} to {@link String} from the available
* {@linkplain #converterFactories() factories}.
*/
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<?, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, String>) converter;
}
}
// Nothing matched. Resort to default converter which just calls toString().
//noinspection unchecked
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
同樣,這里是通過遍歷converterFactories
,找到一個能處理這種類型type
的Converter.Factory
,返回一個 Converter<?, String>
,如果找不到,就使用BuiltInConverters.ToStringConverter.INSTANCE
。查看下BuiltInConverters.ToStringConverter.INSTANCE
源碼:
//BuiltInConverters.java
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
可以看到,默認的StringConverter
就是通過調用paramter
對象的toString
方法,直接將結果類型轉成String
類型。
到這里,我們就明白了:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
接口方法參數user
的類型其實可以不用是String
類型,就算是其他類型也可以,但是默認的StringConverter
調用該類型對象的toString
方法返回的結果要符合你自己需求。
比如,我們現在自定義一個java bean:
public class StringWrapper {
private String content;
public StringWrapper(String content)
{
this.content = content;
}
@Override
public String toString() {
return content;
}
}
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") StringWrapper user);
}
這樣也是可以的,因為StringWrapper.toString
跟我們上面直接定義成的String
最終結果是一樣的。
回到正題,parseParameterAnnotation
中對@Path
的解析最終會返回一個ParameterHandler.Path
對象:
static final class Path<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) {
throw new IllegalArgumentException(
"Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
}
最后,參數解析所有的信息都放入到了全局數據parameterHandlers
中,沒個parameterHandlers[i]
都包含了各個參數的所有注解解析信息。
到這里,
ServiceMethod.Builder.build()
方法也算是解析完畢了。總結一下:ServiceMethod的創建過程主要做了幾件事:
- 根據接口方法返回類型,通過遍歷
retrofit
的adapterFactories
列表,找到適合的CallAdapter<T, R> callAdapter
。 - 根據HTTP返回結果類型,通過遍歷
retrofit
的converterFactories
列表,找到適合的Converter<ResponseBody, T> responseConverter
。 - 對接口方法注解進行解析:
parseMethodAnnotation(Annotation annotation)
。 - 對接口方法參數注解進行解析:
parseParameter
- 完成以上工作后,創建
ServiceMethod
對象。
最后,用一張圖來表達下ServiceMethod
的創建過程:
現在繼續分析
Retrofit.create
中InvocationHandle
r的invoke
剩余部分源碼:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
這里創建了一個okHttpCall
:
final class OkHttpCall<T> implements retrofit2.Call<T> {
···
···
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
···
}
這里可以看到OkHttpCall內部持有一個okhttp3.Call,所以其實OkHttpCall所進行的HTTP請求實際上都是交由okhttp3.Call進行的。
InvocationHandler
的invoke
最后返回了:
return serviceMethod.callAdapter.adapt(okHttpCall);
經過前面的分析,假設我們對Retrofit
沒有經過特殊配置,即Retrofit
采用默認配置,那么:serviceMethod.callAdapter
返回的就是默認的ExecutorCallAdapterFactory.get(Call.class,annotations,retrofit)
//ExecutorCallAdapterFactory.java
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
serviceMethod.callAdapter.adapt(okHttpCall)
返回的就是一個new ExecutorCallbackCall<>(callbackExecutor, okHttpCall)
的對象。
static final class ExecutorCallbackCall<T> implements retrofit2.Call<T> {
final Executor callbackExecutor;
//HTTP請求委托類
final retrofit2.Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
這里可以看到,ExecutorCallbackCall
就是okHttpCall
的代理類,而okHttpCall
又持有okhttp3.Call
實例。因此,進行HTTP請求的過程就明晰了:
ExecutorCallbackCall.enqueue-->okHttpCall.enqueue-->okhttp3.Call.enqueue
ExecutorCallbackCall
持有的Executor callbackExecutor
默認是主線程調度器,會將ExecutorCallbackCall
發送HTTP請求的返回結果回調到主線程上執行。
那我們最后就來看一下發送網絡請求的具體過程。
-
進行網絡請求(同步/異步)
網絡請求是通過我們得到的ExecutorCallbackCall<>(callbackExecutor, okHttpCall)
對象進行請求,這里就只看下異步請求過程:
repos.enqueue(new Callback<ResponseBody>() {/***/});
上面分析知道,ExecutorCallbackCall
內部封裝了網絡請求和線程調度作用,而實際起網絡請求作用的是OkHttpCall
。
那我們就來看下OkHttpCall
的異步網絡請求enqueue
源碼:
@Override
public void enqueue(final Callback<T> callback) {
···
···
okhttp3.Call call;
···
···
call = rawCall = createRawCall();
···
···
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
···
···
callSuccess(response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
···
callback.onFailure(OkHttpCall.this, e);
···
}
···
···
}
}
可以看到,OkHttpCall
里面是通過函數createRawCall
獲得一個真正的能用于HTTP網絡請求的okhttp3.Call
對象,那么我們就來看下createRawCall()
源碼是怎樣構建出一個okhttp3.Call
對象:
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
這里,我們先來看下:
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
serviceMethod.callFactory
默認就是retrofit
的callFactory
,也就是OkHttpClient
,所以這里就是由OkHttpClient
創建出一個真正用于進行HTTP網絡請求的okhttp3.Call
對象。
接下來我們回顧上一行代碼,可以看到是通過serviceMethod.toRequest(args)
構建出一個Request
,此處的args
就是我們接口方法的參數,那么我們就先來看下serviceMethod.toRequest
源碼是怎樣構建一個Request
的:
/** Builds an HTTP request from method arguments. */
Request toRequest(@Nullable Object... args) throws IOException {
//從接口方法注解解析信息
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
//接口方法參數注解解析信息
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
所以我們前面為什么說ServiceMethod
在Retrofit
里面是很重要的,在這里也可以知道,ServiceMethod
既負責解析接口方法,接口參數,又負責從retrofit
那邊獲取合適的CallAdapte
r和Converter
,又要負責將接口解析出來的內容組裝成一個HTTP Request···可以說,ServiceMethod
就是Retrofit
的核心引擎。
回到toRequest
函數,從上面的源碼中可以看到,首先是根據接口方法解析的信息組裝成了一個RequestBuilder
,然后再根據方法參數信息(Object... args
),經由之前解析的參數注解信息可以得到一個最終的RequestBuilder
,由這些信息就可以build
出一個Request
。
toRequest
里面有句代碼是:
handlers[p].apply(requestBuilder, args[p]);
這里其實獲取得到的就是接口方法第p個參數解析出來的效果,舉個例子來說,比如,我們之前handlers[p]
解析出來的是@Path
的信息,那么handlers[p]
就是一個ParameterHandler.Path
類型的對象,而ParameterHandler.Path
是ParameterHandler
靜態內部類,同時也是一個ParameterHandler
子類:
static final class Path<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) {
throw new IllegalArgumentException(
"Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
}
所以,handlers[p].apply(requestBuilder, args[p])
按官網的例子就變成了:
Path.apply(requestBuilder,String user)-->builder.addPathParam(”user", valueConverter.convert("user"), encoded);
而由我們前面的分析,此處的valueConverter
默認是ToStringConverter
:
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
所以valueConverter.convert("user")-->"user".toString()=="user"
,所以最終返回的就是字符串"user"
,所以:
builder.addPathParam(”user", valueConverter.convert("user"), encoded)-->builder.addPathParam(”user", "user", encoded)。
對于@Path
來說,肯定是將參數信息替換掉接口方法注解內容相對路徑的{*}內容,所以,builder.addPathParam
就是實現這個功能的:
void addPathParam(String name, String value, boolean encoded) {
if (relativeUrl == null) {
// The relative URL is cleared when the first query parameter is set.
throw new AssertionError();
}
relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
}
經過以上步驟,就構建出了一個HTTP請求。
最后,我們就可以用這個請求進行真正的網絡發送call.enqueue
,回顧上面OkHttpCall.enqueue
方法,可以看到請求返回結果解析是在:
//OkHttpCall.enqueue片段代碼
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
可以看到,請求成功的時候,會調用parseResponse
得到一個我們需要的Response<T>
類型對象,具體解析方法如下:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
···
···
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
···
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
···
}
parseResponse
就是對得到的rawResponse
進行處理判斷,最后交由到serviceMethod.toResponse
做出最終的轉換。
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
可以看到這里就是用到了數據轉換器Converter<ResponseBody, R>
將HTTP返回結果ResponseBody
轉換成我們自己定義的類型R
(默認的Converter.Factory
是BuiltInConverters
,它所生產的Convert
默認不對ResponseBody
進行轉換)。
所以分析到了這里,Retrofit
整體的流程我們也差不多整理完畢了。
最后進行總結一下:
- 我們要是用
Retrofit
進行HTTP網絡請求的時候,首先要創建一個接口進行HTTP動作描述,之所以用接口是為了后面動態創建一個對應的接口代理類(java的動態代理只能支持接口); - 接口描述創建完成后,通過建造者模式可以配置出一個
retrofit
實例 - 由
retrofit
的`create函數就可以創建出一個接口的動態代理類 - 調用動態代理類的接口方法時,就會被動態代理類攔截,攔截的主要原因就是為了隱式的創建出一個用于HTTP網絡請求的
Call
對象,具體做了3件事:
?1. 解析接口注解內容并保存,功能類為ServiceMethod
。
?2. 創建一個OkHttpCall
對象,OkHttpCall
內部持有okhttp3.Call
實例。OkHttpCall
的作用就是從ServiceMethod
和當前參數獲取得到一個Request
,并通過OkHttpClient
根據這個Request
創建出一個okhttp3.Call
對象。
?3. 最后從ServiceMethod
中拿到一個可以處理接口方法返回類型的CallAdapter
,由其adapt
返回得到一個可以對HTTP請求結果進行線程調度的retrofit2.Call
對象(該Call
對象是OkHttpCall
的代理類)。