使用Retrofit
網(wǎng)上使用Retrofit的好文章很多,我也就不重復(fù)造輪子。給大家推薦一些文章:看了這些文章你如真的理解Retrofit,你會(huì)發(fā)現(xiàn)其實(shí)下面實(shí)現(xiàn)的功能,其實(shí)很多是對(duì)OkHttp的操作,因?yàn)镽etrofit底層請(qǐng)求使用的就是OkHttp,Retrofit的真正的作用就是你可以用注解接口的方式請(qǐng)求。當(dāng)然Retrofit也做了很多細(xì)節(jié)處理,做到了類型安全等。
-
Retrofit官網(wǎng)介紹
官網(wǎng)介紹,基本的介紹和使用,最新版本。 -
Retrofit 2.0:有史以來最大的改進(jìn)
主要講Retrofit1和Retrofit2的不同,以及需要注意的點(diǎn)。例如即使response存在問題onResponse依然被調(diào)用,新的URL拼接等 -
Retrofit 2.0(一) 超能實(shí)踐,完美支持Https傳輸
這個(gè)文章主要介紹:如何Retrofit 開啟Log日志,如何增加header頭部消息 以及添加證書Pinning和如何支持https等 - Retrofit 2.0 超能實(shí)踐(二),Okhttp完美同步持久Cookie實(shí)現(xiàn)免登錄
- Retrofit 2.0 超能實(shí)踐(三),輕松實(shí)現(xiàn)多文件/圖片上傳/Json字符串/表單
- Retrofit 2.0 超能實(shí)踐(四),完成大文件斷點(diǎn)下載
-
Android基于Retrofit2.0+RxJava 封裝的超好用的RetrofitClient工具類
上面的幾篇內(nèi)容,基本上能把工作中遇到使用Retrofit的問題都介紹到了。
解析Retrofit的核心結(jié)構(gòu)
一般使用Retrofit會(huì)分下面幾步
- Retrofit會(huì)把http api請(qǐng)求用java接口的方式呈現(xiàn)。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
- Retrofit會(huì)通過動(dòng)態(tài)代理生成GitHubService。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
- 通過生成的GitHubService,創(chuàng)建不同的call的http請(qǐng)求。通過enqueue方法,或者execute方法,讓其異步或者同步執(zhí)行。
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
核心原理分析
通過Retrofit.create()創(chuàng)建出Service interface的實(shí)例,從而使得Service中配置的方法變得可用,這是Retrofit代碼結(jié)構(gòu)的核心。跟進(jìn)retrofit.create()的方法,首先檢查service是不是接口并且繼承接口,讓后看看是否需要提前創(chuàng)建方法,放入serviceMethodCache中,默認(rèn)不需要。最后就是重點(diǎn)動(dòng)態(tài)代理,創(chuàng)建動(dòng)態(tài)對(duì)象。動(dòng)態(tài)代理的優(yōu)勢(shì)在于可以很方便的對(duì)代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個(gè)代理類中的方法。是因?yàn)樗斜淮韴?zhí)行的方法,都是通過在InvocationHandler中的invoke方法調(diào)用的,所以我們只要在invoke方法中統(tǒng)一處理,就可以對(duì)所有被代理的方法進(jìn)行相同的操作了。具體動(dòng)態(tài)代理相關(guān)內(nèi)容可以看這篇文章:java動(dòng)態(tài)代理實(shí)現(xiàn)與原理
public <T> T create(final Class<T> service) {
//檢查service,是不是接口,是否繼承接口。要求service是接口且不繼承其他接口
Utils.validateServiceInterface(service);
//默認(rèn)為false,判斷是否需要提前l(fā)oadServiceMethod(method);
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 {
//如果方法來自object或者platform,那就正常調(diào)用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//重點(diǎn)內(nèi)容
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
下面是三行代碼就是整個(gè)create方法的核心,創(chuàng)建一個(gè)實(shí)現(xiàn)service接口類的實(shí)例。
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
第一行:ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
ServiceMethod將一個(gè)接口方法適配成為一個(gè)HTTP請(qǐng)求,讀取網(wǎng)絡(luò)請(qǐng)求接口里的方法,并根據(jù)前面配置好的屬性配置serviceMethod對(duì)象。loadServiceMethod方法的作用就是將接口注解解析,并存到serviceMethodCache中。下面的代碼邏輯:如果serviceMethodCache中存在,就直接返回結(jié)果。然后同步以下內(nèi)容操作:再次從serviceMethodCache中嘗試獲取,如果還是沒有,就自己創(chuàng)建,然后將創(chuàng)建的好的對(duì)象放入serviceMechodCache中。
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;
}
如何創(chuàng)建ServiceMethod,就在ServiceMethod.Builder<>(this, method).build()中實(shí)現(xiàn),下面就是源碼,主要作用就是負(fù)責(zé)讀取interface中原方法的信息:返回值類型,請(qǐng)求方法注解,參數(shù)類型,參數(shù)注解。同時(shí)也創(chuàng)建callAdapter,responseConverter等后續(xù)請(qǐng)求和返回?cái)?shù)據(jù)轉(zhuǎn)換會(huì)用到的對(duì)象,同時(shí)調(diào)用parseMethodAnnotation,parseParameter方法將注解的方法和參數(shù)組裝好。然后返回ServiceMethod對(duì)象。
public ServiceMethod build() {
//創(chuàng)建CallAdapter,默認(rèn)創(chuàng)建ExecutorCallAdapterFactory
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?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//請(qǐng)求方法的驗(yàn)證
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
//請(qǐng)求參數(shù)的驗(yàn)證
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);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
第二行:OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
OkHttpCall的創(chuàng)建:下面這行代碼主要負(fù)責(zé)將ServiceMethod封裝近一個(gè)retrofit2.call對(duì)象中。在使用enqueue()方法中,利用ServiceMethod中包含的信息創(chuàng)建一個(gè)okhttp3.Call對(duì)象,并調(diào)用okhttp3.Call對(duì)象來進(jìn)行網(wǎng)絡(luò)請(qǐng)求的發(fā)起,然后對(duì)結(jié)果進(jìn)行處理。也就是說retrofit2.Call包裝了一個(gè)okhttp3.Call,所有的工作都由okhttp3.Call來進(jìn)行處理。一句話就是變成okhttpcall,進(jìn)行真正的網(wǎng)絡(luò)請(qǐng)求。如果是不能再主線程中執(zhí)行的請(qǐng)求,例如下面的enqueue方法:
enqueue方式中明顯的看到用createRawCall方法創(chuàng)建出一個(gè)okhttp3.call的方法,然后讓真實(shí)去做請(qǐng)求的okhttp3.call去做enqueue方法。
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(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 {
call = 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() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@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) {
t.printStackTrace();
}
}
});
}
createRawCall做了什么?erviceMethod.toCall(args)將解析注解得到的請(qǐng)求方法,請(qǐng)求參數(shù)構(gòu)建成一個(gè)okhttp3.call。具體如何構(gòu)建,我也沒有仔細(xì)看過。
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
第三行:serviceMethod.adapt(okHttpCall)
adapt()方法就是把okHttpCall對(duì)象進(jìn)行轉(zhuǎn)化,生成一個(gè)新的retrofit2.Call對(duì)象,這樣就變回去了,上一步將retrofit2.call對(duì)象變成OkHttpCall3.call去進(jìn)行網(wǎng)絡(luò)請(qǐng)求。其實(shí)這個(gè)方法也可以生成別的對(duì)象,如果Retrofit中添加addCallAdapterFactory(RxJava2CallAdapterFactory.create()),Rxjava的Obervable同樣也可以被創(chuàng)建。
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
callAdapter是網(wǎng)絡(luò)請(qǐng)求適配器,將默認(rèn)的網(wǎng)絡(luò)請(qǐng)求執(zhí)行器(OkHttpCall)轉(zhuǎn)換成適合被不同平臺(tái)來調(diào)用的網(wǎng)絡(luò)請(qǐng)求執(zhí)行器形式,通過createCallAdapter()產(chǎn)生,我們一步一步的跟進(jìn),調(diào)用retrofit.callAdapter(returnType, annotations);
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
然后再調(diào)用nextCallAdapter(null, returnType, annotations)
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
在nextCallAdapter()方法中,調(diào)用CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this)來找到adapter,查找callAdapterFactory,在Retrofit中提供了四種CallAdapterFactory: ExecutorCallAdapterFactory(默認(rèn))、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory。
在Retrofit.build()的中會(huì)給callAdapterFactories添加CallAdapterFactorie,如果沒有添加RxJavaCallAdapter之類就按默認(rèn)提供的CallAdapterFactory。
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
boolean isDefaultMethod(Method method) {
return false;
}
@Nullable Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
@Nullable Object... args) throws Throwable {
throw new UnsupportedOperationException();
}
我們知道默認(rèn)的callAdapter來自ExecutorCallAdapterFactory,找到adapt()方法,從okhttp.call適配成retrofit.call。
@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);
}
};
}
進(jìn)入ExecutorCallbackCal中,delegate就是一個(gè)okhttp3.call,有我們的生成的okhttpCall傳入。印證了我們之前收到,無論轉(zhuǎn)化成Retrofit2.call還是RxJava的observable,最后正常的進(jìn)行網(wǎng)絡(luò)請(qǐng)求的還是okhttp3.call。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
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);
}
});
}
});
}
......
}
enqueue方法具有切換功能原因就在這里,new Handler(Looper.getMainLooper())
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);
}
}
}
}
總結(jié)
Retrofit的總體邏輯就是上面內(nèi)容,下面有一篇介紹的比較詳細(xì)
Android:手把手帶你 深入讀懂 Retrofit 2.0 源碼