您好,登錄后才能下訂單哦!
本篇內容主要講解“Retrofit網絡請求和響應處理源碼分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Retrofit網絡請求和響應處理源碼分析”吧!
網絡請求
在使用 Retrofit 發起網絡請求時,我們可以通過定義一個接口并使用 Retrofit 的注解來描述這個接口中的請求,Retrofit 會自動生成一個實現該接口的代理對象。當我們調用這個代理對象的方法時,Retrofit 會根據注解的描述構建一個 Request 對象,并使用 OkHttp 將這個 Request 發送出去。
在 Retrofit 中,我們可以通過 Retrofit#execute
或 Retrofit#enqueue
方法來發送請求。這兩個方法的區別在于,execute
方法會阻塞當前線程直到請求完成,而 enqueue
方法會將請求加入到 OkHttp 的請求隊列中,并在請求完成時通過回調通知我們。
我們先來看一下 execute
方法的實現:
public <T> T execute(Call<T> call) throws IOException { Utils.validateServiceInterface(call.request().tag(), call.request().url().toString()); return (T) callAdapter(call, call.request().tag()).adapt(call).execute(); }
在這個方法中,首先會對接口進行校驗,確保這個接口是有效的。然后我們會根據請求的 Tag 和 URL 來獲取適配器callAdapter
,并使用適配器來執行請求。
適配器的作用是將請求的參數適配成 OkHttp 能夠識別的形式,并將 OkHttp 的響應適配成我們需要的形式。Retrofit 提供了一系列的適配器,包括 Call 適配器、RxJava 適配器、CompletableFuture 適配器等。
我們來看一下 callAdapter
方法的實現:
private CallAdapter<?, ?> callAdapter(Call<?> call, Object tag) { Type responseType = call.request().method().equals("HEAD") ? Void.class : getParameterUpperBound(0, (ParameterizedType) call.request().tag()); return callAdapter(tag, responseType); }
在這個方法中,我們首先根據請求的方法來判斷響應的類型,如果是 HEAD 方法,那么響應的類型就是 Void;否則我們會通過反射來獲取請求的響應類型,并使用這個響應類型來獲取適配器。
獲取適配器的方法是 callAdapter
:
public <R, T> CallAdapter<R, T> callAdapter(Object tag, Type returnType) { // ... for (CallAdapter.Factory factory : adapterFactories) { CallAdapter<?, ?> adapter = factory.get(returnType, annotations, this); if (adapter != null) { return (CallAdapter<R, T>) adapter; } } // ... }
在這個方法中,我們會遍歷所有的適配器工廠,嘗試獲取適配器。在獲取適配器時,我們會將請求的響應類型、注解和 Retrofit 實例作為參數傳入。每個適配器工廠都會判斷這些參數是否符合自己的適配條件,如果符合,就返回一個適配器實例,否則返回 null。在遍歷完所有的適配器工廠之后,如果還沒有獲取到適配器,那么就會拋出一個異常。
獲取到適配器之后,我們就可以使用適配器來執行請求了。在適配器中,我們會將請求參數轉換成 OkHttp 的 Request 對象,并將 OkHttp 的 Response 對象轉換成我們需要的響應類型。具體的實現可以參考 Retrofit 提供的 CallAdapter
接口。
對于 enqueue
方法,我們可以先來看一下 enqueue
方法的實現:
public <T> void enqueue(Call<T> call, Callback<T> callback) { Utils.validateServiceInterface(call.request().tag(), call.request().url().toString()); callAdapter(call, call.request().tag()).adapt(call).enqueue(new CallbackRunnable<>(callback)); }
在這個方法中,我們首先進行接口校驗,然后根據請求的 Tag 和 URL 來獲取適配器,并使用適配器來執行請求。不同的是,在 enqueue
方法中,我們將一個 Callback 對象作為參數傳入適配器的 enqueue
方法中,以便在請求完成后回調通知我們。
在適配器中,我們可以看到 enqueue
方法的實現:
public void enqueue(final Callback<T> callback) { delegate.enqueue(new Callback<Response<T>>() { @Override public void onResponse(Call<Response<T>> call, Response<Response<T>> response) { Response<T> body; try { body = response.body(); } catch (Throwable t) { if (response.code() == 204) { body = null; } else { callback.onFailure(call, t); return; } } if (response.isSuccessful()) { callback.onResponse(call, Response.success(body, response.raw())); } else { callback.onFailure(call, Response.error(response.errorBody(), response.raw())); } } @Override public void onFailure(Call<Response<T>> call, Throwable t) { callback.onFailure(call, t); } }); }
在這個方法中,我們會將傳入的 Callback 對象轉換成一個 Callback<Response<T>>
對象,并使用這個對象來調用 OkHttp 的 enqueue 方法。在請求完成后,我們會將 OkHttp 的 Response 對象轉換成 Retrofit 的 Response 對象,并根據響應碼來判斷請求的結果。如果響應碼表示請求成功,那么我們就調用 Callback 對象的 onResponse
方法;否則就調用 Callback 對象的 onFailure
方法。
在 Retrofit 中,我們可以通過定義一個接口并使用注解來描述我們期望的請求格式和響應格式。例如,我們可以通過 @GET
注解來描述一個 GET 請求,使用 @Query
注解來描述請求參數,使用 @Body
注解來描述請求體,使用 @Headers
注解來描述請求頭等。
在執行請求時,Retrofit 會根據這些注解來自動生成一個對應的請求對象,并將請求對象轉換成 OkHttp 的 Request 對象。在接收響應時,Retrofit 會將 OkHttp 的 Response 對象轉換成一個對應的響應對象,并將響應對象中的數據轉換成我們需要的數據類型。這些轉換工作是通過 Retrofit 的轉換器來完成的,Retrofit 中默認提供了兩個轉換器:GsonConverterFactory
和 JacksonConverterFactory
。我們也可以自定義一個轉換器來實現我們期望的數據轉換。
在 Retrofit 類的構造方法中,我們可以看到 Retrofit 默認使用了 Platform.get()
方法來獲取當前運行平臺的默認轉換器工廠,并將其添加到 converterFactories
中。然后,我們可以使用 addConverterFactory
方法來添加自定義的轉換器工廠。
public Retrofit(Builder builder) { // ... if (builder.converterFactories == null) { converterFactories.add(Platform.get().defaultConverterFactory()); } else { converterFactories.addAll(builder.converterFactories); } // ... } public interface Platform { // ... Converter.Factory defaultConverterFactory(); }
在execute
方法中,我們會調用適配器的 adapt 方法來執行請求,并將返回的 Call 對象轉換成一個響應對象。在轉換過程中,我們會根據響應類型來選擇對應的轉換器來進行轉換。具體的轉換實現可以參考 Retrofit 提供的 Converter
接口和 Converter.Factory
接口。
public <T> T execute(Call<T> call) throws IOException { // ... Response<T> response = call.execute(); if (response.isSuccessful()) { return response.body(); } else { Converter<ResponseBody, ErrorResponse> converter = retrofit.responseBodyConverter( ErrorResponse.class, new Annotation[0]); throw new ApiException(converter.convert(response.errorBody())); } } @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety. public <T> T adapt(Call<T> call) { return (T) new OkHttpCall<>(requestFactory, callFactory, converter, call); } public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { return nextResponseBodyConverter(null, type, annotations); } 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) { return (Converter<ResponseBody, T>) converter; } } throw new IllegalArgumentException( "Could not locate ResponseBody converter for " + type + " with annotations " + Arrays.toString(annotations)); }
以上是 Retrofit 中處理響應的核心代碼。當我們執行一個請求時,Retrofit 會先將請求轉換成 OkHttp 的 Request 對象并發送出去,然后等待響應返回。當響應返回時,Retrofit 會將響應轉換成一個響應對象,并將響應對象中的數據轉換成我們期望的數據類型。這個過程中,我們可以使用 Retrofit 提供的轉換器來自定義數據的轉換規則。
下面是一個示例,演示了如何使用 Retrofit 來發送一個 GET 請求并將響應中的 JSON 數據轉換成一個 Java 對象:
public interface ApiService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build(); ApiService apiService = retrofit.create(ApiService.class); Call<List<Repo>> call = apiService.listRepos("smallmarker"); List<Repo> repos = call.execute().body();
在上面的示例中,我們首先使用 Retrofit 構建器創建一個 Retrofit 實例,并指定了請求的基礎 URL 和轉換器工廠。然后,我們通過調用 create
方法來創建一個 ApiService
的代理對象。最后,我們調用 listRepos
方法來發送一個 GET 請求。
在上面的示例中,我們使用了 Retrofit 的 GsonConverterFactory
來將響應體中的 JSON 數據轉換成 Java 對象。具體實現可以查看 Retrofit 提供的 GsonConverterFactory
類。
public final class GsonConverterFactory extends Converter.Factory { private final Gson gson; private GsonConverterFactory(Gson gson) { this.gson = gson; } public static GsonConverterFactory create() { return create(new Gson()); } public static GsonConverterFactory create(Gson gson) { if (gson == null) throw new NullPointerException("gson == null"); return new GsonConverterFactory(gson); } @Override public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter<>(gson, adapter); } @Override public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonRequestBodyConverter<>(gson, adapter); } }
可以看到,GsonConverterFactory
繼承了 Retrofit 的 Converter.Factory
類,并重寫了其中的 responseBodyConverter
方法和 requestBodyConverter
方法。在 responseBodyConverter
方法中,我們將響應體中的 JSON 數據轉換成 Java 對象,而在 requestBodyConverter
方法中,我們將 Java 對象轉換成請求體中的 JSON 數據。
除了 GsonConverterFactory
以外,Retrofit 還提供了其他的轉換器,如 JacksonConverterFactory、MoshiConverterFactory
等,我們可以根據需要選擇適合自己的轉換器。
總的來說,Retrofit 中網絡請求和響應處理的核心代碼非常簡潔明了。我們只需要通過定義接口來描述請求和響應,然后使用 Retrofit 的動態代理機制來將接口轉換成一個實際的實現類,并通過 Retrofit 的配置來指定請求和響應的轉換器即可。這種方式大大簡化了網絡請求的流程,使得我們可以更加專注于業務邏輯的處理。
到此,相信大家對“Retrofit網絡請求和響應處理源碼分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。