本平臺的文章更新會有延遲逗宜,大家可以關(guān)注微信公眾號-顧林海同波,包括年底前會更新kotlin由淺入深系列教程允懂,目前計劃在微信公眾號進(jìn)行首發(fā)厕怜,如果大家想獲取最新教程,請關(guān)注微信公眾號蕾总,謝謝!
在上一節(jié)《Android小知識-剖析Retrofit中ServiceMethod相關(guān)參數(shù)以及創(chuàng)建過程》介紹了動態(tài)代理類中三行核心代碼的第一行酣倾,通過loadServiceMethod方法獲取ServiceMethod對象,在loadServiceMethod方法中先會檢查緩存集合中是否有對應(yīng)網(wǎng)絡(luò)請求接口方法的ServiceMethod對象谤专,如果不存在就通過Builder模式創(chuàng)建躁锡,同時介紹了ServiceMethod內(nèi)部的一些成員變量,其實(shí)ServiceMethod就是對網(wǎng)絡(luò)請求接口內(nèi)部一個個方法的封裝置侍,通過解析方法內(nèi)部或方法上的注解來封裝ServiceMethod對象映之。這節(jié)來介紹三行核心代碼的剩余兩行拦焚。
public <T> T create(final Class<T> 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 {
...
//核心代碼1
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//核心代碼2
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//核心代碼3
return serviceMethod.adapt(okHttpCall);
}
});
}
在核心代碼2處創(chuàng)建OkHttpCall,OkHttpCall是Call的實(shí)現(xiàn)類杠输,在Retrofit中內(nèi)部是通過OkHttp來進(jìn)行網(wǎng)絡(luò)的請求赎败,這個OkHttpCall就是對OkHttp請求的封裝。
final class OkHttpCall<T> implements Call<T> {
....
private @Nullable okhttp3.Call rawCall;
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
}
在OkHttpCall中可以看到rawCall蠢甲,它是OkHttp的Call僵刮,這也驗(yàn)證之前所說的內(nèi)部會通過OkHttp來實(shí)現(xiàn)網(wǎng)絡(luò)請求,OkHttpCall構(gòu)造函數(shù)傳入兩個參數(shù)鹦牛,serviceMethod對象和args網(wǎng)絡(luò)請求參數(shù)搞糕,接著看核心代碼3。
return serviceMethod.adapt(okHttpCall);
serviceMethod的adapt方法中會調(diào)用callAdatper的adapter方法曼追,通過適配器的adapt方法來將OkHttpCall轉(zhuǎn)換成其他平臺使用的對象窍仰,這個callAdapter是在創(chuàng)建serviceMethod時通過構(gòu)建者模式創(chuàng)建的,它代表網(wǎng)絡(luò)請求的適配器礼殊,這里使用的RxJava平臺驹吮。
回到一開始的實(shí)例代碼:
private void initRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://icould.glh/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
NetworkInterface networkInterface = retrofit.create(NetworkInterface.class);
Map<String, String> params = new HashMap<>();
params.put("newsId", "1");
params.put("token", "yud133f");
Call call = networkInterface.getNewsDetails(params);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
System.out.println(response.body());
}
@Override
public void onFailure(Call call, Throwable t) {
System.out.println("請求錯誤");
}
});
}
通過networkInterface接口調(diào)用getNewsDetails是不行的,因此在Retrofit的create獲取網(wǎng)絡(luò)接口的動態(tài)代理晶伦,在執(zhí)行networkInterface的getNewDetails方法時碟狞,通過動態(tài)代理攔截,并執(zhí)行動態(tài)代理對象內(nèi)InvocationHandler中的invoke方法婚陪,將OkHttpCall轉(zhuǎn)換成RxJava平臺的適用的Call族沃,而這個OkHttpCall對象是對OkHttp網(wǎng)絡(luò)庫的封裝,最后返回OkHttpCall類型的Call對象近忙,有了這個Call對象就可以進(jìn)行同步或異步請求竭业,OkHttpCall內(nèi)提供了同步請求方法execute和異步請求方法enqueue,接著下來重點(diǎn)分析這兩個方法及舍。
在Retrofit同步請求流程中未辆,首先需要對網(wǎng)絡(luò)請求接口中方法以及參數(shù)進(jìn)行解析,通過ParameterHandler進(jìn)行解析锯玛,然后根據(jù)ServiceMethod對象創(chuàng)建OkHttp的Request對象咐柜,ServiceMethod對象內(nèi)部包含了網(wǎng)絡(luò)請求的所有信息,它是對網(wǎng)絡(luò)接口方法的封裝攘残,有了Request對象后就可以通過OkHttp這個庫來進(jìn)行網(wǎng)絡(luò)請求拙友,最后解析服務(wù)端給客戶端返回的數(shù)據(jù),通過converter數(shù)據(jù)轉(zhuǎn)換器來完成數(shù)據(jù)的轉(zhuǎn)換歼郭。
OkHttpCall的同步請求execute方法:
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
下面貼出execute局部代碼遗契,方便分析。
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
...
}
...
}
上面代碼中一開始創(chuàng)建了一個OkHttp的call對象病曾,下面是一個同步代碼塊牍蜂,通過判斷executed是否執(zhí)行過通過請求漾根,如果執(zhí)行過就會拋出異常,接著判斷creationFailure鲫竞,不為null時辐怕,判斷異常類型并拋出異常,execute方法的前段部分就是對異常的判斷从绘。
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
...
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
...
}
當(dāng)沒有任何異常時寄疏,將rawCall也就是OkHttp的原生call賦值給局部變量call,當(dāng)call為null時僵井,通過createRawCall方法創(chuàng)建OkHttp的Call對象以及Request陕截。
進(jìn)入createRawCall方法:
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
內(nèi)部通過serviceMethod的toCall方法將傳入的請求參數(shù)轉(zhuǎn)換成Call對象。
進(jìn)入serviceMethod的toCall方法:
okhttp3.Call toCall(@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;
...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
RequestBuilder內(nèi)部保存著網(wǎng)絡(luò)請求的相關(guān)參數(shù)驹沿,接著在for循環(huán)中通過ParameterHandler對參數(shù)進(jìn)行解析艘策,最后通過callFactory的newCall創(chuàng)建OkHttp的Call對象,newCall內(nèi)部傳入的是Request對象,通過requestBuilder.build()創(chuàng)建Request對象十籍,到這里將OkHttp的Call對象返回給execute方法內(nèi)部的成員變量call以及OkHttpCall的成員變量rawCall外盯。
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
...
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
有了OkHttp的Call之后,就通過call.execute()進(jìn)行阻塞式的同步請求婴栽,并將返回的Response傳入parseResponse方法中。
進(jìn)入parseResponse方法:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
...
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
...
}
}
只看核心代碼,通過調(diào)用serviceMethod的toResponse方法返回body合砂,進(jìn)入toResponse方法,看它到底做了哪些操作源织。
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
原來是調(diào)用了數(shù)據(jù)轉(zhuǎn)換器將OkHttp返回的Response轉(zhuǎn)換成Java對象翩伪,這里我們使用的Gson,也就是通過Gson將服務(wù)器返回的數(shù)據(jù)轉(zhuǎn)換成我們需要的Java對象谈息,最后通過Response的success方法將返回的Java對象封裝成Response缘屹。
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
...
return Response.success(body, rawResponse);
}
進(jìn)入Response的success方法:
public static <T> Response<T> success(@Nullable T body, okhttp3.Response rawResponse) {
...
return new Response<>(rawResponse, body, null);
}
返回創(chuàng)建好的Response,將body也就是我們的Java對象傳過去侠仇。
Response的構(gòu)造函數(shù):
private Response(okhttp3.Response rawResponse, @Nullable T body,
@Nullable ResponseBody errorBody) {
this.rawResponse = rawResponse;
this.body = body;
this.errorBody = errorBody;
}
到這里大家應(yīng)該很熟悉了轻姿,我們利用Retrofit進(jìn)行網(wǎng)絡(luò)的同步或異步請求,最終會返回一個Response對象并通過response.body來獲取結(jié)果逻炊,這個body就是通過轉(zhuǎn)換器轉(zhuǎn)換好的Java對象互亮。
接下來分析異步請求:
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
System.out.println(response.body());
}
@Override
public void onFailure(Call call, Throwable t) {
System.out.println("請求錯誤");
}
});
執(zhí)行異步請求的流程和同步類似,只不過異步請求的結(jié)果是通過回調(diào)來傳遞的余素,異步是通過enqueue方法來執(zhí)行的豹休,而這個Call的實(shí)現(xiàn)類是OkHttpCall,進(jìn)入OkHttpCall的enqueue方法桨吊。
OkHttpCall的enqueue方法(上半部分):
@Override public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
...
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;
}
}
}
...
}
可以發(fā)現(xiàn)enqueue的上半部分與上面介紹同步請求時是一樣的威根,創(chuàng)建OkHttp的Call窑眯,并檢查相關(guān)異常,如果call為null医窿,就通過createRawCall方法創(chuàng)建OkHttp的Call以及請求所需要的Request磅甩。
OkHttpCall的enqueue方法(下半部分):
@Override public void enqueue(final Callback<T> callback) {
...
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();
}
}
...
});
}
上面這段代碼不用我講,大家也應(yīng)該知道就是通過OkHttp的Call的enqueue方法進(jìn)行異步請求姥卢,關(guān)于OkHttp相關(guān)知識可以閱讀之前寫的OkHttp分析的相關(guān)系列教程卷要,在OkHttp的Call的enqueue方法的回調(diào)方法onResponse方法中,將返回的Response通過parseResponse方法轉(zhuǎn)換成Java對象并返回Retrofit的Response對象独榴,通過前面?zhèn)魅氲腃allback對象將Response回調(diào)給客戶端僧叉。
到這里關(guān)于Retrofit網(wǎng)絡(luò)請求框架的封裝就講解完畢了!