概述
App的開發(fā)過程中,少不了和網(wǎng)絡(luò)打交道。從最開始用的Android Async Http到Volley再到現(xiàn)在的Retrofit,Retrofit的使用方式給了我很深的印象店乐,于是就看了它的源碼實(shí)現(xiàn),加深對(duì)它的學(xué)習(xí)和理解呻袭。
Retrofit介紹
retrofit其實(shí)不是一個(gè)網(wǎng)絡(luò)請(qǐng)求庫(kù)眨八,算是一個(gè)請(qǐng)求庫(kù)上層的一個(gè)使用封裝,發(fā)請(qǐng)求的實(shí)現(xiàn)還是用的OKHttp左电。官方文檔中有這么一句話:Use annotations to describe the HTTP request廉侧。即使用注解的方式去描述Http請(qǐng)求。Retrofit的實(shí)際作用就是讓開發(fā)者可以通過注解很方便的產(chǎn)生請(qǐng)求并發(fā)起請(qǐng)求篓足,不需要自己去構(gòu)建Request段誊。
Retrofit使用及源碼分析
每個(gè)請(qǐng)求都要有API,Retrofit的API定義方式是通過接口的形式栈拖,如下代碼:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
很多人可能會(huì)覺得困惑连舍,沒看到API地址吖,這里只有一個(gè)相對(duì)的"users/{user}/repos"涩哟,別急索赏,我們?cè)偻驴词褂谩?/p>
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
首先是在創(chuàng)建Retrofit時(shí)指定了baseUrl盼玄,這個(gè)就是用此Retrofit創(chuàng)建的請(qǐng)求都是以這個(gè)baseUrl為基礎(chǔ)的。
然后通過retrofit.create(GitHubService.class);來創(chuàng)建一個(gè)GitHubService 的實(shí)例潜腻,這里使用的是動(dòng)態(tài)代理埃儿,來看看這里面的實(shí)現(xiàn)吧。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
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, 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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
Utils.validateServiceInterface(service);是對(duì)傳入的service進(jìn)行校驗(yàn)砾赔,Retrofit要求接口定義必需是interface蝌箍,并且不能extend其它的interface青灼。
Proxy.newProxyInstance這個(gè)就是動(dòng)態(tài)代理的實(shí)現(xiàn)了暴心。Java動(dòng)態(tài)代理就是給了程序員一種可能:當(dāng)你要調(diào)用某個(gè)Class的方法前或后,插入你想要執(zhí)行的代碼杂拨。Retrofit實(shí)現(xiàn)動(dòng)態(tài)代理就是要在調(diào)用接口的方法時(shí)专普,通過反射去解析注解,解析參數(shù)弹沽,動(dòng)態(tài)去生成一個(gè)Request請(qǐng)求檀夹,這也就印證了官方的Use annotations to describe the HTTP request這句話了。
具體的轉(zhuǎn)換在 ServiceMethod serviceMethod = loadServiceMethod(method);里策橘,來看下loadServiceMethod的實(shí)現(xiàn):
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
可以看到炸渡,這里做了一個(gè)緩存,避免多次生成ServiceMethod丽已,可以提高性能蚌堵。我們?cè)偃タ聪戮唧w的ServiceMethod生成邏輯:
public ServiceMethod build() {
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);
}
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).");
}
}
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);
}
這里初始化了callAdapter、responseType沛婴、responseConverter這些變量吼畏,用于發(fā)起請(qǐng)求和解析response的。這里有一行很關(guān)鍵的代碼就是:
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
這里對(duì)方法的注解進(jìn)行了分析嘁灯,來看下里面的邏輯吧:
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;
}
}
哇泻蚊,這就是我們使用的請(qǐng)求類型注解了,像GET丑婿、POST性雄、PUT都有呢,原來就是在這里進(jìn)行解析的羹奉。
回過頭來繼續(xù)看create函數(shù):
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
Retrofit默認(rèn)使用OkHttp來發(fā)起請(qǐng)求秒旋,這里還做了一個(gè)適配,通過callAdapter把請(qǐng)求轉(zhuǎn)成想要的類型尘奏,比如RxJava2CallAdapter滩褥,就會(huì)把請(qǐng)求傳成Observable<?>類型。
源碼分析就先到這里了炫加,相信也有助于大家去理解Retrofit的使用了原理了瑰煎。
總結(jié)
Retrofit并不是一個(gè)網(wǎng)絡(luò)請(qǐng)求庫(kù)铺然,是一個(gè)網(wǎng)絡(luò)請(qǐng)求的上層封裝,提供友好的接口讓使用者自定義請(qǐng)求酒甸。源碼里使用了大量的工廠模式魄健,適配器模式,設(shè)計(jì)感很強(qiáng)插勤,方便擴(kuò)展和自定義沽瘦。官方提供了RxJava的支持,和RxJava結(jié)合起來用還是很爽的农尖。如果服務(wù)器的接口是用Restful的析恋,那是再合適不過了!盛卡!