OkHttp與Retrofit 的區別與聯繫是怎樣的?git
參考答案:
OkHttp和Retrofit都是目前流行網絡開源框架github
封裝不一樣:
Retrofit封裝了具體的請求,線程切換以及數據轉換。
retrofit經過使用代理,外觀,策略模式對okhttp進行了封裝
OkHttp 是基於Http協議封裝的一套請求客戶端面試
職責不一樣:
Retrofit主要負責應用層面的封裝,面向開發者,方便使用,好比請求參數,響應數據的處理,錯誤處理等等。
OkHttp主要負責socket部分的優化與封裝,好比網絡訪問,多路複用,buffer緩存,數據壓縮等等。
正則表達式
(順手留下GitHub連接,須要獲取相關面試等內容的能夠本身去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)api
Retrofit
能夠說和 OkHttp
是親兄弟了,它們都是由 Square 公司推出的網絡請求庫,而且 Retrofit
其實是基於 OkHttp
實現的,它在 OkHttp
現有功能的基礎上進行了封裝,支持經過註解進行網絡請求參數的配置,同時對數據返回後的解析、序列化進行了統一的包裝,甚至在近期引入了對協程對支持。緩存
今天就讓咱們一塊兒來看看 Retrofit
是如何在 OkHttp
這樣一個已經固定的框架的基礎上,優雅的進行封裝並拓展功能的。網絡
基本使用
咱們首先來看看 Retrofit 的基本使用,來對它有個大體的瞭解。app
首先,咱們能夠構建一個以下的請求 Service 類,它裏面對各個請求的方法及參數經過註解進行了標註:框架
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
以後,咱們能夠構建一個 Retrofit
對象,並經過 Retrofit.create
方法傳入對應 class
從而構建對應的 Service
對象:異步
Retrofit retrofit = new Retrofit.Builder() baseUrl("https://api.github.com/") build(); } GitHubService service = retrofit.create(GitHubService.class);
以後,咱們調用 service
中對應的方法,就能夠獲取到 Call 對象了。
經過對 Call 對象調用 enqueue
就能夠實現對請求的異步調用,而經過 execute
方法則能夠實現請求的同步調用。
Retrofit 採用了 Builder 模式進行了構建,在 Builder 中能夠進行很是多的配置,其中能夠對 baseUrl
、okhttpClient
、converterFactory
、callAdapterFactory
等進行設置。
這裏沒什麼特別的,都是一些簡單的賦值,就再也不關注了,咱們只須要看看最後 Retrofit 被傳入了哪些參數。它最後調用了下面這個構造函數對參數進行了初始化。
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = converterFactories; // Copy+unmodifiable at call site. this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; }
接着咱們看到本身定義的 interface
是如何僅僅靠傳遞 class
給 Retrofit.create
就能實現實例的獲取的,它明明只是個接口呀?
public <T> T create(final Class<T> service) { // 對 Service 的接口進行檢測 validateServiceInterface(service); // 經過動態代理構建代理對象 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // Object 類的方法照常調用 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } // 若是是對應平臺自己的類就有的方法,照常調用 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } // 不然經過 loadServiceMethod 方法獲取到對應 Method 並 invoke return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } }); }
能夠看到,實際上 Service
對象的獲取是經過動態代理實現的。這裏首先經過 validateServiceInterface
方法對接口進行了檢測,以後經過動態代理對該接口進行了代理。
對於 Object
類自己獨有以及對應平臺自己就存在的方法,就照常調用,不然經過 loadServiceMethod
對 Service
中對應的 Method
對象進行處理,以後對其調用 invoke
方法。
這裏說明了 Retrofit
不是在建立 Service
接口對應對象時就當即對全部該接口中的全部方法都進行註解的解析,而是採用了在方法被調用時才進行註解的解析這種懶加載的思想。
接着咱們看看 validateServiceInterface
方法:
private void validateServiceInterface(Class<?> service) { // 判斷是不是接口 if (!service.isInterface()) { throw new IllegalArgumentException("API declarations must be interfaces."); } // 判斷該接口及其繼承的全部接口是否包含了範型參數,若是包含則拋出異常 Deque<Class<?>> check = new ArrayDeque<>(1); check.add(service); while (!check.isEmpty()) { Class<?> candidate = check.removeFirst(); if (candidate.getTypeParameters().length != 0) { StringBuilder message = new StringBuilder("Type parameters are unsupported on ").append(candidate.getName()); if (candidate != service) { message.append(" which is an interface of ").append(service.getName()); } throw new IllegalArgumentException(message.toString()); } Collections.addAll(check, candidate.getInterfaces()); } // 若是在建立Retrofit時設置了很急切地對Service的方法進行處理,則對非平臺獨有且非static的方法經過 loadServiceMethod 方法進行處理。 if (validateEagerly) { Platform platform = Platform.get(); for (Method method : service.getDeclaredMethods()) { if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) { loadServiceMethod(method); } } } }
首先,這個方法對 service
進行了檢測,保證了它是一個接口而且它和它繼承的類中沒有範型參數。
以後若是在 Retrofit 建立時設置 validateEagerly
爲 true 的話,會對 Service 中全部非平臺獨有且非static的方法經過 loadServiceMethod
方法提早進行處理
loadServiceMethod
究竟作了些什麼:ServiceMethod<?> loadServiceMethod(Method method) { ServiceMethod<?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); } } return result; }
首先它會採用 Double Check 的方式嘗試從 serviceMethodCache
緩存中獲取 ServiceMethod
對象,若是獲取不到則經過 ServiceMethod.parseAnnotations
方法對該 Method 的註解進行處理並將獲得的 ServiceMethod
對象加入了緩存。
也就是說爲了不屢次對方法的註解進行處理,Retrofit 採用了一個 serviceMethodCache
對解析後的 ServiceMethod
進行緩存。
接着咱們就來看看,parseAnnotations
方法是如何對方法的註解進行解析的。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); Type returnType = method.getGenericReturnType(); if (Utils.hasUnresolvableType(returnType)) { throw methodError(method, "Method return type must not include a type variable or wildcard: %s", returnType); } if (returnType == void.class) { throw methodError(method, "Service methods cannot return void."); } return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); }
這裏先經過 RequestFactory.parseAnnotations
方法對註解解析並得到了一個 RequestFactory
對象。
以後又經過 HttpServiceMethod.parseAnnotations
方法傳入了 requestFactory
繼續進行註解的解析並得到 ServiceMethod
對象
咱們先看看 RequestFactory.parseAnnotations
:
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { return new Builder(retrofit, method).build(); }
它把 Method
傳入 Builder
從而構建了一個新的 RequestFactory
:
Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; this.methodAnnotations = method.getAnnotations(); this.parameterTypes = method.getGenericParameterTypes(); this.parameterAnnotationsArray = method.getParameterAnnotations(); }
Builder 中經過反射獲取到method
所包含的註解、參數包含的範型以及參數的註解。
接着看看 build
方法:
RequestFactory build() { for (Annotation annotation : methodAnnotations) { // 遍歷方法註解對每一個註解進行解析 parseMethodAnnotation(annotation); } // ...異常的處理 // 對參數進行解析 int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) { parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter); } // ... 異常的處理 return new RequestFactory(this); }
在 build 方法中主要是對方法的每一個註解調用了 parseMethodAnnotation
進行了解析,而且對每一個參數調用了 parseParamter
方法解析爲了 ParamterHandler
對象。
parseMethodAnnotation
的代碼以下:
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); } 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(method, "@Headers annotation is empty."); } headers = parseHeaders(headersToParse); } else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError(method, "Only one encoding annotation is allowed."); } isMultipart = true; } else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError(method, "Only one encoding annotation is allowed."); } isFormEncoded = true; } }
這裏實際上就是對每一種 HTTP 所支持的類型進行了支持,獲取到了對應註解的中的 url,並調用parseHttpMethodAndPath
進行處理,同時對 Headers 註解則是經過 parseHeaders
進行了處理。
對於 Method 和 Path,經過 parseHttpMethodAndPath
進行了參數的賦值:
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { if (this.httpMethod != null) { throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod); } this.httpMethod = httpMethod; this.hasBody = hasBody; if (value.isEmpty()) { return; } // Get the relative URL path and existing query string, if present. int question = value.indexOf('?'); if (question != -1 && question < value.length() - 1) { // Ensure the query string does not have any named parameters. String queryParams = value.substring(question + 1); Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams); if (queryParamMatcher.find()) { throw methodError(method, "URL query string \"%s\" must not have replace block. "+ "For dynamic query parameters use @Query.", queryParams); } } this.relativeUrl = value; this.relativeUrlParamNames = parsePathParameters(value); }
這裏實際上就是對不一樣 HTTP 請求方式和 Path 進行了賦值,同時經過正則表達式保證了這個接口的 Path 中沒有包含參數。
private Headers parseHeaders(String[] headers) { Headers.Builder builder = new Headers.Builder(); for (String header : headers) { int colon = header.indexOf(':'); if (colon == -1 || colon == 0 || colon == header.length() - 1) { throw methodError(method, "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header); } String headerName = header.substring(0, colon); String headerValue = header.substring(colon + 1).trim(); if ("Content-Type".equalsIgnoreCase(headerName)) { try { contentType = MediaType.get(headerValue); } catch (IllegalArgumentException e) { throw methodError(method, e, "Malformed content type: %s", headerValue); } } else { builder.add(headerName, headerValue); } } return builder.build(); }
而對於 Headers 則是將傳遞進來的 Headers
列表解析爲了對應的 Headers
對象。
private @Nullable ParameterHandler<?> parseParameter( int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) { ParameterHandler<?> result = null; if (annotations != null) { for (Annotation annotation : annotations) { // 對每一個註解經過 parseParameterAnnotation 進行解析 ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation); if (annotationAction == null) { continue; } if (result != null) { throw parameterError(method, p, "Multiple Retrofit annotations found, only one allowed."); } result = annotationAction; } } if (result == null) { // 在協程的狀況下對進行特殊處理 if (allowContinuation) { try { if (Utils.getRawType(parameterType) == Continuation.class) { isKotlinSuspendFunction = true; return null; } } catch (NoClassDefFoundError ignored) { } } throw parameterError(method, p, "No Retrofit annotation found."); } return result; }
而 parseParamterAnnotation
方法的代碼太長了,這裏就再也不貼了,它對方法的每一個註解都進行了獨有的處理,並返回了對應的 ParamterHandler
。
能夠發現,RequestFactory.parseAnnotations
的主要做用就是完成對方法註解信息的解析,從而用於產生對應的 Request
。
HttpServiceMethod.parseAnnotations
:static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotation[] annotations = method.getAnnotations(); Type adapterType; if (isKotlinSuspendFunction) { // 若是方法是 kotlin 中的 suspend 方法 Type[] parameterTypes = method.getGenericParameterTypes(); // 獲取 Continuation 的範型參數,它就是 suspend 方法的返回值類型 Type responseType = Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]); // 若是 Continuation 的範型參數是 Response,則說明它須要的是 Response,那麼將 continuationWantsResponse 置爲 true; if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) { // Unwrap the actual body type from Response<T>. responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType); continuationWantsResponse = true; } else { // TODO figure out if type is nullable or not // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class) // Find the entry for method // Determine if return type is nullable or not } adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType); annotations = SkipCallbackExecutorImpl.ensurePresent(annotations); } else { // 不然獲取方法返回值的範型參數,即爲請求須要的返回值的類型 adapterType = method.getGenericReturnType(); } // 經過 createCallAdapter 方法建立 CallAdapter 對象 CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); if (responseType == okhttp3.Response.class) { throw methodError(method, "'" + getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } if (responseType == Response.class) { throw methodError(method, "Response must include generic type (e.g., Response<String>)"); } // TODO support Unit for Kotlin? if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) { throw methodError(method, "HEAD method must use Void as response type."); } // 經過 createResponseConverter 方法建立 Converter對象 Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { // 不是suspend方法的話則直接建立並返回一個 CallAdapted 對象 return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } }
這裏的代碼很是很是長,大體可概括爲下面的步驟:
1. 若是這個方法是 Kotlin 中的 suspend 方法,因爲由協程實現,所以須要獲取
Continuation
的範型參數,這個參數就是請求返回值的真正類型。
2. 若是suspend
方法返回值是Response
,則說明它須要的是 Response 而不是具體的類型,那麼將continuationWantsResponse
置爲 true;
3. 若是不是suspend
方法,則返回值的範型參數的類型就是請求返回值的真正類型(Call<ReturnType>
則ReturnType
纔是真正通過轉換後須要的類型)。
4. 經過createCallAdapter
方法建立CallAdapter
對象,它是用於將Call<ResponseT>
對象適配爲須要的類型ReturnT
對象的。
5. 拿到CallAdapter
後,獲取到了Response
的類型,並進行了校驗。
6. 經過createResponseConverter
方法獲取Converter
對象,它能夠完成從ResponseBody
到Response
類型ResponseT
的轉換。
7. 若是並不是 Kotlin 的 suspend 方法,則直接傳入CallAdapter
及 Converter,建立CallAdapted
對象。
8. 不然根據 suspend 方法須要的是Response
仍是具體的類型,分別返回SuspendForResponse
和SuspendForBody
對象。
能夠發現,新版的 Retrofit 對 Kotlin 的協程進行了支持。HttpServiceMethod.parseAnnotations
的主要做用就是建立 CallAdapter
以及 Converter 對象,並構建對應 HttpServiceMethod
。
CallAdapter
是用於將Call<R>
對象適配爲須要的類型 T 對象的。它的聲明以下:
public interface CallAdapter<R, T> { // 返回 Response 的類型 Type responseType(); // 將 Call<R> 轉換爲 T 類型 T adapt(Call<R> call); }
咱們先看看 createCallAdapter
方法是如何對它建立的:
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { try { //noinspection unchecked return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create call adapter for %s", returnType); } }
它調用了 retrofit.callAdapter
方法:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); }
以後調用到 retrofit.nextCallAdapter
方法:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { Objects.requireNonNull(returnType, "returnType == null"); Objects.requireNonNull(annotations, "annotations == null"); int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { // 遍歷 callAdapterFactories,嘗試建立 CallAdapter CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } // ...不存在對應的 CallAdapterFactory,拋出異常 }
這裏其實是遍歷了建立 Retrofit 對象時傳遞的 CallAdapter.Factory
列表嘗試去建立 CallAdapter
。若是這些 CallAdapter.Factory
都沒法處理這個對應的 returnType
以及 annotations
的話,則會拋出異常。(前面 Factory 的優先級更高)
Retrofit 中有一個默認的 CallAdapter
工廠 DefaultCallAdapterFactory
,它的優先級比全部自定義工廠要低,它在建立時會傳入一個 Executor
,咱們能夠看到它的 get 方法:
@Override public @Nullable CallAdapter<?, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } if (!(returnType instanceof ParameterizedType)) { throw new IllegalArgumentException( "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>"); } final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType); final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null: callbackExecutor; return new CallAdapter<Object, Call<?>>() { @Override public Type responseType() { return responseType; } @Override public Call<Object> adapt(Call<Object> call) { return executor == null ? call: new ExecutorCallbackCall<>(executor, call); } }; }
能夠看到,在沒有 Executor
時,它不對 Call 進行修改,在有指定 Executor 時,則會將其包裝爲 ExecutorCallbackCall
。通常來講這個 Executor 就是建立 Retrofit 時指定的 callbackExecutor
。
這個 callbackExecutor
其實是用來指定調用 Callback
的線程的,從而使得 Callback
並不必定是在主線程被回調:
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) { Objects.requireNonNull(callback, "callback == null"); // 對 Callback 進行了包裝,經過 callbackExecutor 進行回調 delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute(() -> { 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(() -> callback.onFailure(ExecutorCallbackCall.this, t)); } }); } // ... }
能夠看到,這裏實際上只是對 Callback 進行了包裝,經過傳遞的 Executor 進行回調,從而對 callbackExecutor
進行支持。
接着咱們看看 Converter
類,它是一個接口,用於將類型 F 的數據轉換爲類型 T:
public interface Converter<F, T> { @Nullable T convert(F value) throws IOException; // ... }
接着咱們看看 createResponseConverter
是如何對它進行建立的:
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create converter for %s", responseType); } }
轉調到了 retrofit.responseBodyConverter
:
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { return nextResponseBodyConverter(null, type, annotations); }
轉調到了 nextResponseBodyConverter
:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { Objects.requireNonNull(type, "type == null"); Objects.requireNonNull(annotations, "annotations == null"); int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } } // 沒有找到對應的 ConverterFactory 進行處理,拋出異常 }
能夠看到,這裏與 CallAdapter
工廠相似,遍歷建立 Retrofit 時傳入的 Converter.Factory
列表,嘗試進行建立,若是沒有工廠能對其進行處理,拋出異常。(前面 Factory 的優先級更高)
Retrofit
中內置了兩個 Converter.Factory
,分別是 BuiltInConverters
以及 OptionalConverterFactory
。
其中 BuiltInConverters
的優先級比全部自定義工廠要高,以免其餘工廠覆蓋它的方法,而 OptionalConverterFactory
的優先級比全部自定義工廠的優先級更低。
BuiltInConverters
中實現了多個轉換器如將 ResponseBody
轉換爲 Void 或 Unit,將 Object 轉換爲 String 等。
OptionalConverterFactory
是經過 platform 獲取到的 defaultConverterFactories
,它是爲了支持 Java 8 的 Optional 而實現的,Optional 是 Java 8 引入的用來解決空指針異常的類。
接着咱們看看以前建立的 ServiceMethod
類,它是一個抽象類,須要子類對 invoke 方法進行實現。
abstract class ServiceMethod<T> { abstract @Nullable T invoke(Object[] args); }
它的子類就是前面提到的 HttpServiceMethod
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> { @Override final @Nullable ReturnT invoke(Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args); }
HttpServiceMethod
的 invoke 方法很是簡單,它構造了一個 OkHttpCall
,而後經過 adapt 這個虛函數來實現對 Call 的轉換。它的子類只須要實現 adapt 從而對 Call 進行轉換便可。
它共有三個子類,首先就是並不是使用協程的狀況下的 CallAdapted
類,另外兩個子類則是在使用協程的狀況下爲了配合協程的 SuspendForResponse
以及 SuspendForBody
類
CallAdapted
類繼承自 HttpServiceMethod
類,並經過傳遞進來的 CallAdapter
對 Call 進行了轉換。
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { private final CallAdapter<ResponseT, ReturnT> callAdapter; CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; } @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) { return callAdapter.adapt(call); } }
SuspendForResponse
類首先根據傳遞進來的 Call 構造了一個參數爲 Response<ResponseT>
的 Continuation
對象而後經過 Kotlin 實現的 awaitResponse
方法將 call 的 enqueue
異步回調過程封裝爲了一個 suspend 的函數。
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> { private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter; SuspendForResponse(RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, Call<ResponseT>> callAdapter) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; } @Override protected Object adapt(Call<ResponseT> call, Object[] args) { call = callAdapter.adapt(call); //noinspection unchecked Checked by reflection inside RequestFactory. Continuation<Response<ResponseT>> continuation = (Continuation<Response<ResponseT>>) args[args.length - 1]; // See SuspendForBody for explanation about this try/catch. try { return KotlinExtensions.awaitResponse(call, continuation); } catch (Exception e) { return KotlinExtensions.suspendAndThrow(e, continuation); } } }
awaitResponse
方法以下:
suspend fun <T : Any> Call<T>.awaitResponse(): Response<T> { return suspendCancellableCoroutine { continuation -> continuation.invokeOnCancellation { cancel() } enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { continuation.resume(response) } override fun onFailure(call: Call<T>, t: Throwable) { continuation.resumeWithException(t) } }) } }
能夠看到,分別經過在 onResponse
和 onFailure
中調用 continuation.resume
和 continuation.resumeWithException
從而對協程進行支持。
而 SuspendForBody
則是根據傳遞進來的 Call 構造了一個 Continuation<ResponseT>
對象而後經過 Kotlin 實現的 await 或 awaitNullable
方法將 call 的 enqueue
異步回調過程封裝爲了一個 suspend 的函數。
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> { private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter; private final boolean isNullable; SuspendForBody(RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, Call<ResponseT>> callAdapter, boolean isNullable) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; this.isNullable = isNullable; } @Override protected Object adapt(Call<ResponseT> call, Object[] args) { call = callAdapter.adapt(call); //noinspection unchecked Checked by reflection inside RequestFactory. Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1]; // Calls to OkHttp Call.enqueue() like those inside await and awaitNullable can sometimes // invoke the supplied callback with an exception before the invoking stack frame can return. // Coroutines will intercept the subsequent invocation of the Continuation and throw the // exception synchronously. A Java Proxy cannot throw checked exceptions without them being // in an UndeclaredThrowableException, it is intercepted and supplied to a helper which will // force suspension to occur so that it can be instead delivered to the continuation to // bypass this restriction. try { return isNullable ? KotlinExtensions.awaitNullable(call, continuation) : KotlinExtensions.await(call, continuation); } catch (Exception e) { return KotlinExtensions.suspendAndThrow(e, continuation); } } }
Call 其實是一個接口,它提供了 execute
、enqueue
、cancel
等接口用於實現請求,當咱們須要請求一個接口的時候,只須要調用其 enqueue
或 execute
方法便可。
public interface Call<T> extends Cloneable { Response<T> execute() throws IOException; void enqueue(Callback<T> callback); boolean isExecuted(); void cancel(); boolean isCanceled(); Call<T> clone(); Request request(); }
從前面的過程當中咱們能夠了解到,若是咱們沒有傳入 CalAdapter
的話,默認狀況下返回的 Call 其實是 OkHttpCall
對象,讓咱們經過它來看看 Retrofit 如何基於 OkHttp
實現的網絡請求:
首先讓咱們看看 enqueue
的代碼:
@Override public void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); okhttp3.Call call; Throwable failure; // 加鎖,對狀態進行設置並經過 createRawCall 方法建立 okhttp3.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; } } } if (failure != null) { callback.onFailure(this, failure); return; } // 若是外界取消該任務,則調用 okhttp3.Call.cancel if (canceled) { call.cancel(); } // 經過 okhttp3.Call.enqueue 將消息入隊 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { // 得到結果後經過 parseResponse 進行解析 response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } try { // 解析完成後經過 onResponse 進行回調 callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); // TODO this is not great } } @Override public void onFailure(okhttp3.Call call, IOException e) { // 請求失敗調用 callFailure 回調失敗請求 callFailure(e); } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); // TODO this is not great } } }); }
enqueue
的代碼看似多,實際上比較簡單,主要分爲如下幾步:
1. 加鎖,對執行狀態進行設置,若不存在 rawCall 則調用 createRawCall 方法建立 okhttp3.Call 對象。
2. 若是外界取消該任務,則調用 okhttp3.Call.cancel
3. 經過 okhttp3.Call.enqueue 將消息入隊
4. 若得到 Response,則經過 parseResponse 方法對 Response 進行解析,解析完成後經過 onResponse 回調解析結果。
5. 若請求失敗,經過 callFailure 方法調用 onFailure 回調請求失敗。
能夠發現一個小細節,Retrofit 對已經建立的 okhttp3.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 { 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()); }
也很是簡單:
1.首先加鎖後對執行狀態進行設置,若不存在
rawCall
則調用createRawCall
方法建立okhttp3.Call
對象。
2.若是外界取消該任務,則調用okhttp3.Call.cancel
。
3.若得到Response
,則經過parseResponse
方法對Response
進行解析並返回
接着讓咱們看看 createRawCall
方法:
private okhttp3.Call createRawCall() throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }
它其實是調用了 callFactory
的 newCall
方法進行建立,而傳入的 okhttp3.Request
則是經過 requestFactory.create
建立的:
okhttp3.Request create(Object[] args) throws IOException { @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types. ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; int argumentCount = args.length; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount+ ") doesn't match expected count (" + handlers.length + ")"); } RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); if (isKotlinSuspendFunction) { // The Continuation is the last parameter and the handlers array contains null at that index. argumentCount--; } List<Object> argumentList = new ArrayList<>(argumentCount); for (int p = 0; p < argumentCount; p++) { argumentList.add(args[p]); handlers[p].apply(requestBuilder, args[p]); } return requestBuilder.get(.tag(Invocation.class, new Invocation(method, argumentList)) .build(); }
這裏首先構建了一個 RequestBuilder
,以後經過遍歷 ParamterHandler
列表並調用其 apply 方法將參數應用到 RequestBuilder
中。
接着咱們看看 parseResponse
是如何對 Response 進行解析的:
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(); // ... ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { T body = responseConverter.convert(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; } }
能夠看到,它會經過 Converter.convert
方法將 Response 的 body
轉換爲咱們所須要的類型。
那麼到這裏,Retrofit
的源碼咱們就基本上看完了,能夠發現它的代碼中基本不多涉及到對網絡請求的處理,基本都是對於 OkHttp
的封裝,在 OkHttp
現有的 API 上提供了一套更便於使用的框架。
Retrofit
很好地向咱們證實了,如何在一套已經固定的 API 上,以最優雅的方式對現有的框架進行封裝,拓展出更爲強大的功能。
Retrofit
的註解是一種運行時註解,它經過動態代理對 Service 對象進行建立,經過反射對註解進行解析,這樣雖然會有必定性能的損耗,但性能的損耗卻帶來了十分易用的 API。用戶所寫的 Service 接口中,每個 ServiceMethod
都對應了一個接口。
對於 Service
的建立,它是經過動態代理,對每一個接口內定義的方法進行了代理,若設置 validateEagerly
了則會在建立 Service 接口對象時進行註解的解析以及 ServiceMethod
的建立,不然會在方法調用時再建立對應的 ServiceMethod
對象,在屢次調用的狀況下,它經過 serviceMethodCache
對已經解析的 ServiceMethod
進行了緩存從而避免了重複解析帶來的性能損耗。
這個對象的建立首先會通過 RequestFactory.parseAnnotations
對方法中的註解進行解析:
parseHttpMethodAndPath
方法獲取註解對應的請求方式以及註解中的 url 等信息並保存起來,在建立請求的時候設置進 RequestBuilder
。RequestBuilder
。ParamterHandler
,在建立請求的時候,會經過它的 apply 方法將參數提交到 RequestBuilder
中。以後,這個對象會經過 HttpServiceMethod.parseAnnotations
對 ServiceMethod
對象進行建立,它在建立的過程當中同時進行了接口對應的 CallAdapter
以及 Converter
的建立。
其中,CallAdapter
用於將Call<R>
對象適配爲須要的類型 T 對象,也就是對 Call 進行轉換。
而 Converter
則是用於將 F 類型的數據轉換爲 T,每每是用於對 Response
的 body 進行轉換。
對於 CallAdapter
和 Converter
都是經過它們對應的工廠類進行建立,建立時會根據工廠列表的順序從前向後嘗試進行建立,也就是說在工廠列表中越靠前的工廠其優先級越大。
同時,Retrofit
還引入了對 Continuation
協程的支持,它會將 ServerMethod
最終包裝爲一個 suspend
方法從而對協程進行支持。
Retrofit
的網絡請求的執行依賴於 OkHttp
,它首先會經過 RequestFactory
進行 Request 的構造,它的參數經過前面解析的信息得來。以後會將這個 Request 包裝爲一個 okhttp3.Call
,在同步和異步請求時分別調用其對應的 execute 及 enqueue
方法。同時,爲了不okhttp3.Call
的重複建立,它對以前建立的 okhttp3.Call
進行了複用。
(順手留下GitHub連接,須要獲取相關面試等內容的能夠本身去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)