Retrofit是對OKHttp的封裝,簡化了網(wǎng)絡請求伴郁。具體使用參見官方文檔耿战。本文分析的代碼是 retrofit2.3.0
先看一下retrofit官方的實例:
public final class SimpleService {
public static final String API_URL = "https://api.github.com";
public static class Contributor {
public final String login;
public final int contributions;
public Contributor(String login, int contributions) {
this.login = login;
this.contributions = contributions;
}
}
// 1
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
public static void main(String... args) throws IOException {
// Create a very simple REST adapter which points the GitHub API.
//2
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
//3
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
//4
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
//5
List<Contributor> contributors = call.execute().body();
//6
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
}
其中Retrofit的步驟:
- 創(chuàng)建一個接口(GitHub 接口)。
- 創(chuàng)建一個Retrofit對象焊傅,并提供baseUrl剂陡,ConverterFactory等。
- 創(chuàng)建一個實現(xiàn)接口的一個代理對象狐胎。
- 調(diào)用接口方法并返回一個Call對象鸭栖。
- 執(zhí)行exceute()同步請求。
- 解析Response握巢。
接下來我們以這個步驟一步一步來看晕鹊。
1、接口
retrofit2.http
包暴浦,里面全部是定義HTTP請求的Java注解溅话,比如GET
、POST
歌焦、PUT
飞几、DELETE
、Headers
独撇、Path
循狰、Query
等等。所以在接口里用注解方式定義請求類型等券勺。
2绪钥、Retrofit對象
Retrofit 對象的創(chuàng)建還是用目前流行的Build模式創(chuàng)建。
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
....
/**
* 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) {
//1
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
// 2
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
//3
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
- 通過build() 創(chuàng)建 OkHttpClient對象关炼。
- 設置一個CallAdapterFactory.
- 添加各種Converter 轉換工廠程腹。
這里的AdapterFactory 默認使用DefaultCallAdapterFactory
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@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 call;
}
};
}
}
這個DefaultCallAdapterFactory 下面會用到。
3儒拂、retrofit.create() 返回4 中的 Call對象
通過retrofit.create 高镐,動態(tài)創(chuàng)建一個接口代理對象。
public <T> T create(final Class<T> service) {
//判斷是否是接口.
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//Proxy.newProxyInstance 返回一個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.
//如果這個方法是對象里面的水醋,則直接調(diào)用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//創(chuàng)建OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
這里通過Proxy.newProxyInstance 返回一個service 的代理對象。這里涉及到java動態(tài)代理知識蒜哀,不熟悉的同學先去了解動態(tài)代理斩箫。
當我們調(diào)用這個代理的方法時,比如調(diào)用contributors() 方法時會調(diào)用invoke()方法。
在這個代理里面先通過loadServiceMethod() 獲取到ServiceMethod 乘客,在通過ServiceMethod 創(chuàng)建OkHttpCall狐血,然后調(diào)用CallAdapter 的 adapt 返回一個實體T。
接下去看 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); 通過loadServiceMethod() 獲取到ServiceMethod易核。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//構建ServiceMethod
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
ServiceMethod 的構建還是用到build模式匈织。
public ServiceMethod build() {
//1
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?");
}
//2
responseConverter = createResponseConverter();
// 3
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).");
}
}
//4
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);
}
- 創(chuàng)建 CallAdapter
- 創(chuàng)建轉換器,將返回的結果進行轉換牡直。
- 處理請求的Annotation 注解缀匕。
- 處理參數(shù)的注解。
看一下createCallAdapter()
private CallAdapter<T, R> createCallAdapter() {
//獲取Type
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
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
//獲取 CallAdapter
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)到retrofit中的callAdapter()方法碰逸。
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
//從 adapterFactories中獲取CallAdapter
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
nextCallAdapter中 通過adapterFactories集合獲取到CallAdapter弦追,而默認的adapterFactories中是我們在Retrofit.build中添加的一個默認CallAdapterFactory也就是上面說的DefaultCallAdapterFactory
最后在create中return serviceMethod.callAdapter.adapt(okHttpCall); 也就是調(diào)用DefaultCallAdapterFactory 中的adapt().
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
直接返回傳進來的Call也就是OkHttpCall。
5花竞、exceute()
接下來執(zhí)行Call.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 {
//1
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();
}
//2
return parseResponse(call.execute());
}
- 真正的Call是通過createRawCall() 實現(xiàn)。
- 將返回的Response進行包裝约急。
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
//1
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
-
這里調(diào)用 OkHttp的 newCall()零远,開始進入OkHttp的網(wǎng)絡請求。關于OkHttp的源碼分析厌蔽,看這里
?
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) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
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;
}
}
這里講OkHttp返回的Response通過Converter轉換器包裝成我們定義的Response<T> 類型返回回去牵辣。
總結
Retrofit就是對OkHttp 進行封裝,Retrofit本身沒有提供網(wǎng)絡訪問的能力奴饮,也是通過OkHttp去實現(xiàn)的纬向。