整體結構
Retrofit通過動態代理的方式,將我們聲明的interface轉換成一個請求,
通過靜態代理,將我們去請求交給okhttpclient去執行。
使用方法
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl("https://github.com/");
builder.addConverterFactory(GsonConverterFactory.create());
builder.addConverterFactory(GsonConverterFactory.create());
Retrofit build = builder.build();
GitInterfae gitInterfae = build.create(GitInterfae.class);
Call<List<String>> azewz = gitInterfae.listRepos("azewz");
azewz.enqueue(new Callback<List<String>>() {
@Override
public void onResponse(Call<List<String>> call, Response<List<String>> response) {
Log.i("TAG","請求成功");
}
@Override
public void onFailure(Call<List<String>> call, Throwable t) {
Log.i("TAG", "請求失敗");
}
});
- 構件Buidler
確定平臺
Builder初始化一個內建的Converters
- 設定baseURL
- build.create(API.class); 構件一個OkHttp中call的靜態代理
- 執行Call的實例,實際是調用OkHttp的call類
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);
}
});
}
- 當 Call<List<String>> azewz = gitInterfae.listRepos("azewz");就會執行動態代理中的handler的invoke,進行執行。
loadServiceMethod將接口中聲明的方法轉換成我們一個ServiceMethod實例,包含了CallAdapter,RespenseConvert和請求的所有信息,例如http的頭信息,參數信息等。這里會有一
個緩存,當改方法已經被實例化成ServiceMethod,將可以直接重緩存mapserviceMethodCache
中取出。
OKHttpCall就是okhttp的靜態代理類。
當執行enqueue時,才發起請求。 - 當請求結果完成后,在OkHttpCall,使用parseResponse()解析返回的數據
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) { //異常處理
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) { //請求成功,但是是沒有數據的
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody); //調用我們的Convert類的轉換方法,
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
204 No Content
服務器成功處理了請求,但不需要返回任何實體內容,并且希望返回更新了的元信息。響應可能通過實體頭部的形式,返回新的或更新后的元信息。如果存在這些頭部信息,則應當與所請求的變量相呼應。
如果客戶端是瀏覽器的話,那么用戶瀏覽器應保留發送了該請求的頁面,而不產生任何文檔視圖上的變化,即使按照規范新的或更新后的元信息應當被應用到用戶瀏覽器活動視圖中的文檔。
由于204響應被禁止包含任何消息體,因此它始終以消息頭后的第一個空行結尾。
205 Reset Content
服務器成功處理了請求,且沒有返回任何內容。但是與204響應不同,返回此狀態碼的響應要求請求者重置文檔視圖。該響應主要是被用于接受用戶輸入后,立即重置表單,以便用戶能夠輕松地開始另一次輸入。
與204響應一樣,該響應也被禁止包含任何消息體,且以消息頭后的第一個空行結束。
自定義Convert
繼承 extends Converter.Factory
final class JacksonResponseBodyConverter<T> implements Converter<ResponseBody, T>
final class JacksonRequestBodyConverter<T> implements Converter<T, RequestBody>