就目前來講Retrofit2使用的已至關的普遍,那麼咱們先來了解下兩個問題:java
1 . 什麼是Retrofit?python
Retrofit是針對於Android/Java的、基於okHttp的、一種輕量級且安全的、並使用註解方式的網絡請求框架。android
2 . 咱們爲何要使用Retrofit,它有哪些優點?git
首先,Retrofit使用註解方式,大大簡化了咱們的URL拼寫形式,並且註解含義一目瞭然,簡單易懂;github
其次,Retrofit使用簡單,結構井井有條,每一步都能清晰的表達出之因此要使用的寓意;json
再者,Retrofit支持同步和異步執行,使得請求變得異常簡單,只要調用enqueue/execute便可完成;api
最後,Retrofit更大自由度的支持咱們自定義的業務邏輯,如自定義Converters。緩存
好,知道了Retrofit是什麼,有了哪些優點,如今咱們來學習下怎麼使用。安全
在使用以前,你必須先導入必要的jar包,以androidStudio爲例:服務器
添加依賴:
compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2'
由於Retrofit2是依賴okHttp請求的,並且請查看它的META-INF->META-INF\maven\com.squareup.retrofit2\retrofit->pom.xml文件,
<dependencies> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> </dependency> ... </dependencies>
因而可知,它確實是依賴okHttp,okHttp有會依賴okio因此它會制動的把這兩個包也導入進來。
添加權限:
既然要請求網絡,在咱們android手機上是必需要有訪問網絡的權限的,下面把權限添加進來
<uses-permission android:name="android.permission.INTERNET"/>
好了,下面開始介紹怎麼使用Retrofit,既然它是使用註解的請求方式來完成請求URL的拼接,那麼咱們就按註解的不一樣來分別學習:
首先,咱們須要建立一個java接口,用於存放請求方法的:
public interface GitHubService { }
而後逐步在該方法中添加咱們所須要的方法(按照請求方式):
1 :Get : 是咱們最多見的請求方法,它是用來獲取數據請求的。
①:直接經過URL獲取網絡內容:
public interface GitHubService { @GET("users/octocat/repos") Call<List<Repo>> listRepos(); }
在這裏咱們定義了一個listRepos()的方法,經過@GET註解標識爲get請求,請求的URL爲「users/octocat/repos」。
而後看看Retrofit是怎麼調用的,代碼以下:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class); Call<List<Repo>> repos = service.listRepos(); repos.enqueue(new Callback<List<Repo>>(){ @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response){ } @Override public void onFailure(Call<List<Repo>> call, Throwable t){ } });
代碼解釋:首先獲取Retrofit對象,而後經過動態代理獲取到所定義的接口,經過調用接口裏面的方法獲取到Call類型返回值,最後進行網絡請求操做(這裏不詳細說明Retrofit 實現原理,後面會對它進行源碼解析),這裏必需要說的是請求URL的拼接:在構建Retrofit對象時調用baseUrl所傳入一個String類型的地址,這個地址在調用service.listRepos()時會把@GET("users/octocat/repos")的URL拼接在尾部。
ok,這樣就完成了,咱們此次的請求,可是咱們不能每次請求都要建立一個方法呀?這時咱們就會想起動態的構建URL了
②:動態獲取URL地址:@Path
咱們再上面的基礎上進行修改,以下:
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user);
這裏在Get註解中包含{user},它所對應的是@Path註解中的「user」,它所標示的正是String user,而咱們再使用Retrofit對象動態代理的獲取到GitHubService,當調用listRepos時,咱們就必須傳入一個String類型的User,如:
... Call<List<Repo>> repos = service.listRepos("octocat"); ...
如上代碼,其餘的代碼都是不變的,而咱們只須要使用@Path註解就徹底的實現了動態的URL地址了,是否是很方便呢,這還不算什麼,一般狀況下,咱們去獲取一些網絡信息,由於信息量太大,咱們會分類去獲取,也就是攜帶一些必要的元素進行過濾,那咱們該怎麼實現呢?其實也很簡單,由於Retrofit已經爲咱們封裝好了註解,請看下面(官網實例):
③:動態指定條件獲取信息:@Query
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
咱們只須要使用@Query註解便可完成咱們的需求,在@Query("sort")中,short就比如是URL請求地址中的鍵,而它說對應的String sort中的sort則是它的值。
可是咱們想,在網絡請求中通常爲了更精確的查找到咱們所須要的數據,過濾更多不須要的無關的東西,咱們每每須要攜帶多個請求參數,固然可使用@Query註解,可是太麻煩,很長,容易遺漏和出錯,那有沒有更簡單的方法呢,有,固然後,咱們能夠直接放到一個map鍵值對中:
④:動態指定條件組獲取信息:@QueryMap
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
使用@QueryMap註解能夠分別地從Map集合中獲取到元素,而後進行逐個的拼接在一塊兒。
ok,到這裏,咱們使用@Get註解已經能夠完成絕大部分的查詢任務了,下面咱們再來看看另外一種經常使用的請求方式--post
2 POST : 一種用於攜帶傳輸數據的請求方式
稍微瞭解點Http的同窗們,可能都會知道:相對於get請求方式把數據存放在uri地址欄中,post請求傳輸的數據時存放在請求體中,因此post才能作到對數據的大小無限制。而在Retrofit中,它又是怎麼使用的呢?請看下面:
①:攜帶數據類型爲對象時:@Body
@POST("users/new") Call<User> createUser(@Body User user);
當咱們的請求數據爲某對象時Retrofit是這麼處理使用的:
首先,Retrofit用@POST註解,標明這個是post的請求方式,裏面是請求的url;
其次,Retrofit仿照http直接提供了@Body註解,也就相似於直接把咱們要傳輸的數據放在了body請求體中,這樣應用能夠更好的方便咱們理解。
來看下應用:
Call<List<User>> repos = service.createUser(new User(1, "管滿滿", "28", "http://write.blog.csdn.net/postlist"));
這樣咱們直接把一個新的User對象利用註解@Body存放在body請求體,並隨着請求的執行傳輸過去了。
可是有同窗在這該有疑問了,Retrofit就只能傳輸的數據爲對象嗎?固然不是,下面請看
②:攜帶數據類型爲表單鍵值對時:@Field
@FormUrlEncoded @POST("user/edit") Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
當咱們要攜帶的請求數據爲表單時,一般會以鍵值對的方式呈現,那麼Retrofit也爲咱們考慮了這種狀況,它首先用到@FormUrlEncoded註解來標明這是一個表單請求,而後在咱們的請求方法中使用@Field註解來標示所對應的String類型數據的鍵,從而組成一組鍵值對進行傳遞。
那你是否是有該有疑問了,假如我是要上傳一個文件呢?
③:單文件上傳時:@Part
@Multipart @PUT("user/photo") Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
此時在上傳文件時,咱們須要用@Multipart註解註明,它表示容許多個@Part,@Part則對應的一個RequestBody 對象,RequestBody 則是一個多類型的,固然也是包括文件的。下面看看使用
File file = new File(Environment.getExternalStorageDirectory(), "ic_launcher.png"); RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), file); RequestBody descriptionRequestBody = RequestBody.create(null, "this is photo."); Call<User> call = service.updateUser(photoRequestBody, descriptionRequestBody);
這裏咱們建立了兩個RequestBody 對象,而後調用咱們定義的updateUser方法,並把RequestBody傳遞進入,這樣就實現了文件的上傳。是否是很簡單呢?
相比單文件上傳,Retrofit還進一步提供了多文件上傳的方式:
④:多文件上傳時:@PartMap
@Multipart @PUT("user/photo") Call<User> updateUser(@PartMap Map<String, RequestBody> photos, @Part("description") RequestBody description);
這裏其實和單文件上傳是差很少的,只是使用一個集合類型的Map封裝了文件,並用@PartMap註解來標示起來。其餘的都同樣,這裏就很少講了。
3 Header : 一種用於攜帶消息頭的請求方式
Http請求中,爲了防止攻擊或是過濾掉不安全的訪問或是爲添加特殊加密的訪問等等以減輕服務器的壓力和保證請求的安全,一般都會在消息頭中攜帶一些特殊的消息頭處理。Retrofit也爲咱們提供了該請求方式:
@Headers("Cache-Control: max-age=640000") @GET("widget/list") Call<List<Widget>> widgetList(); ----------------------------------------------------------- @Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" }) @GET("users/{username}") Call<User> getUser(@Path("username") String username);
以上兩種是靜態的爲Http請求添加消息頭,只須要使用@Headers註解,以鍵值對的方式存放便可,若是須要添加多個消息頭,則使用{}包含起來,如上所示。但要注意,即便有相同名字得消息頭也不會被覆蓋,並共同的存放在消息頭中。
固然有靜態添加那相對的也就有動態的添加消息頭了,方法以下:
@GET("user") Call<User> getUser(@Header("Authorization") String authorization)
使用@Header註解能夠爲一個請求動態的添加消息頭,假如@Header對應的消息頭爲空的話,則會被忽略,不然會以它的.toString()方式輸出。
ok,到這裏已基本講解完Retrofit的使用,還有兩個重要但簡單的方法也必須在這裏提一下:
1 call.cancel();它能夠終止正在進行的請求,程序只要一旦調用到它,無論請求是否在終止都會被中止掉。
2 call.clone();當你想要屢次請求一個接口的時候,直接用 clone 的方法來生產一個新的,不然將會報錯,由於當你獲得一個call實例,咱們調用它的 execute 方法,可是這個方法只能調用一次。屢次調用則發生異常。
好了,關於Retrofit的使用咱們就講這麼多,接下來咱們從源碼的角度簡單的解析下它的實現原理。
首先先看一下Retrofit2標準示例
Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); GitHubService service = retrofit.create(GitHubService.class); service.enqueue(); service.execute();
由上面咱們基本能夠看出,Retrofit是經過構造者模式建立出來的,那麼咱們就來看看Builder這個構造器的源碼:
public static final class Builder { ... Builder(Platform platform) { this.platform = platform; converterFactories.add(new BuiltInConverters()); } public Builder() { this(Platform.get()); } public Builder client(OkHttpClient client) { return callFactory(checkNotNull(client, "client == null")); } public Builder callFactory(okhttp3.Call.Factory factory) { this.callFactory = checkNotNull(factory, "factory == null"); return this; } public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); HttpUrl httpUrl = HttpUrl.parse(baseUrl); if (httpUrl == null) { throw new IllegalArgumentException("Illegal URL: " + baseUrl); } return baseUrl(httpUrl); } public Builder baseUrl(HttpUrl baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); List<String> pathSegments = baseUrl.pathSegments(); if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this.baseUrl = baseUrl; return this; } public Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(checkNotNull(factory, "factory == null")); return this; } public Builder addCallAdapterFactory(CallAdapter.Factory factory) { adapterFactories.add(checkNotNull(factory, "factory == null")); return this; } public Builder callbackExecutor(Executor executor) { this.callbackExecutor = checkNotNull(executor, "executor == null"); return this; } public Builder validateEagerly(boolean validateEagerly) { this.validateEagerly = validateEagerly; return this; } public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); } }
源碼講解:
1:當咱們使用new Retrofit.Builder()來建立時,在Builder構造器中,首先就得到當前的設備平臺信息,而且把內置的轉換器工廠(BuiltInConverters)加添到工廠集合中,它的主要做用就是當使用多種Converters的時候可以正確的引導並找到能夠消耗該類型的轉化器。
2:從咱們的基本示例中看到有調用到.baseUrl(BASE_URL)這個方法,實際上沒當使用Retrofit時,該方法都是必須傳入的,而且還不能爲空,從源碼中能夠看出,當baseUrl方法傳進的參數來看,若是爲空的話將會拋出NullPointerException空指針異常。
3:addConverterFactory該方法是傳入一個轉換器工廠,它主要是對數據轉化用的,請網絡請求獲取的數據,將會在這裏被轉化成咱們所須要的數據類型,好比經過Gson將json數據轉化成對象類型。
4 : 從源碼中,咱們看到還有一個client方法,這個是可選的,若是沒有傳入則就默認爲OkHttpClient,在這裏能夠對OkHttpClient作一些操做,好比添加攔截器打印log等
5:callbackExecutor該方法從名字上看能夠得知應該是回調執行者,也就是Call對象從網絡服務獲取數據以後轉換到UI主線程中。
6:addCallAdapterFactory該方法主要是針對Call轉換了,好比對Rxjava的支持,從返回的call對象轉化爲Observable對象。
7:最後調用build()方法,經過new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);構造方法把所須要的對象傳遞到Retrofit對象中。
ok,當咱們經過Builder構造器構造出Retrofit對象時,而後經過Retrofit.create()方法是怎麼把咱們所定義的接口轉化成接口實例的呢?來看下create()源碼:
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(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, 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); } }); }
當看到Proxy時,是否是多少有點明悟了呢?沒錯就是動態代理,動態代理其實已經封裝的很簡單了,主要使用newProxyInstance()方法來返回一個類的代理實例,其中它內部須要傳遞一個類的加載器,類自己以及一個InvocationHandler處理器,主要的動做都是在InvocationHandler中進行的,它裏面只有一個方法invoke()方法,每當咱們調用代理類裏面的方法時invoke()都會被執行,而且咱們能夠從該方法的參數中獲取到所須要的一切信息,好比從method中獲取到方法名,從args中獲取到方法名中的參數信息等。
而Retrofit在這裏使用到動態代理也不會例外:
首先,經過method把它轉換成ServiceMethod ;
而後,經過serviceMethod, args獲取到okHttpCall 對象;
最後,再把okHttpCall進一步封裝並返回Call對象。
下面來逐步詳解。
1:將method把它轉換成ServiceMethod
ServiceMethod serviceMethod = loadServiceMethod(method); ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
loadServiceMethod源碼方法中很是的好理解,主要就是經過ServiceMethod.Builder()方法來構建ServiceMethod,並把它給緩存取來,以便下次能夠直接回去ServiceMethod。那下面咱們再來看看它是怎麼構建ServiceMethod方法的:
public Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; this.methodAnnotations = method.getAnnotations(); this.parameterTypes = method.getGenericParameterTypes(); this.parameterAnnotationsArray = method.getParameterAnnotations(); } public ServiceMethod build() { 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?"); } responseConverter = createResponseConverter(); ... return new ServiceMethod<>(this); }
首先在Builder()中初始化一些參數,而後在build()中返回一個new ServiceMethod<>(this)對象。
下面來詳細的解釋下build()方法,徹底理解了該方法則便於理解下面的全部執行流程。
①:構建CallAdapter對象,該對象將會在第三步中起着相當重要的做用。
如今咱們先看看它是怎麼構建CallAdapter對象的:createCallAdapter()方法源碼以下:
private CallAdapter<?> createCallAdapter() { 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[] annotations = method.getAnnotations(); try { return 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); } }
在createCallAdapter方法中主要作的是事情就是獲取到method的類型和註解,而後調用retrofit.callAdapter(returnType, annotations);方法:
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } public CallAdapter<?> nextCallAdapter(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++) { CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } ... }
展轉到Retrofit中nextCallAdapter()中,在for 循環中分別從adapterFactories中來獲取CallAdapter對象,可是adapterFactories中有哪些CallAdapter對象呢,這就須要返回到構建Retrofit對象中的Builder 構造器中查看了
public static final class Builder { ... public Builder addCallAdapterFactory(CallAdapter.Factory factory) { adapterFactories.add(checkNotNull(factory, "factory == null")); return this; } ... public Retrofit build() { List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); ... } } CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { if (callbackExecutor != null) { return new ExecutorCallAdapterFactory(callbackExecutor); } return DefaultCallAdapterFactory.INSTANCE; }
從上面的代碼中能夠看到,無論有沒有經過addCallAdapterFactory添加CallAdapter,adapterFactories集合至少都會有一個ExecutorCallAdapterFactory對象。當咱們從adapterFactories集合中回去CallAdapter對象時,那咱們都會得到ExecutorCallAdapterFactory這個對象。而這個對象將在第三步中和後面執行同步或異步請求時起着相當重要的做用。
②:構建responseConverter轉換器對象,它的做用是尋找適合的數據類型轉化
該對象的構建和構建CallAdapter對象的流程基本是一致的,這裏就不在贅述。同窗們可自行查看源碼。
2:經過serviceMethod, args獲取到okHttpCall 對象
第二步相對比較簡單,就是對象傳遞:
OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) { this.serviceMethod = serviceMethod; this.args = args; }
3:把okHttpCall進一步封裝並返回Call對象
這一步也是一句話 return serviceMethod.callAdapter.adapt(okHttpCall);可是想理解清楚必須先把第一步理解透徹,經過第一步咱們找獲得serviceMethod.callAdapter就是ExecutorCallAdapterFactory對象,那麼調用.adapt(okHttpCall)把okHttpCall怎麼進行封裝呢?看看源碼:
<R> T adapt(Call<R> call);
一看,嚇死寶寶了,就這麼一句,這是嘛呀,可是通過第一步的分析,咱們已知道serviceMethod.callAdapter就是ExecutorCallAdapterFactory,那麼咱們能夠看看在ExecutorCallAdapterFactory類中有沒有發現CallAdapter的另類應用呢,一看,果不其然在重寫父類的get()方法中咱們找到了答案:
@Override public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Call<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> Call<R> adapt(Call<R> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; }
當看到return new CallAdapter中的adapt(Call
ok,當咱們獲得接口的代理實例以後,經過代理接口調用裏面的方法,就會觸發InvocationHandler對象中的invoke方法,從而完成上面的三個步驟而且返回一個Call對象,經過Call對象就能夠去完成咱們的請求了,Retrofit爲咱們提供兩種請求方式,一種是同步,一種是異步。咱們這裏就以異步方式來說解:
service.enqueue(new Callback<List<User>>() { @Override public void onResponse(Call<List<User>> call, Response<List<User>> response) { Log.d("response body",response.body()); } @Override public void onFailure(Call<BoardInfo> call, Throwable t) { Log.i("response Throwable",t.getMessage().toString()); } });
從上面咱們能夠看到enqueue方法中有一個回調函數,回調函數裏面重寫了兩個方法分別表明請求成功和失敗的方法,可是咱們想知道它是怎麼實現的原理呢?那麼請往下面看:
在上面獲取接口的代理實例時,經過代理接口調用裏面的方法獲取一個Call對象,咱們上面也分析了其實這個Call對象就是ExecutorCallbackCall,那麼咱們來看看它裏面是怎麼實現的?
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) { if (callback == null) throw new NullPointerException("callback == null"); delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run() { if (delegate.isCanceled()) { 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(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); }
在ExecutorCallbackCall類中,封裝了兩個對象一個是callbackExecutor,它主要是把如今運行的線程切換到主線程中去,一個是delegate對象,這個對象就是真真正正的執行網絡操做的對象,那麼它的真身究竟是什麼呢?還記得咱們在獲取代理接口第三步執行的serviceMethod.callAdapter.adapt(okHttpCall)的分析吧,通過展轉幾步終於把okHttpCall傳遞到了new ExecutorCallbackCall<>(callbackExecutor, call);中,而後看看ExecutorCallbackCall的構造方法:
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; }
由此能夠明白delegate 就是okHttpCall對象,那麼咱們在看看okHttpCall是怎麼執行異步網絡請求的:
@Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("callback == null"); okhttp3.Call call; Throwable failure; 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) { failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } callSuccess(response); } @Override public void onFailure(okhttp3.Call call, IOException e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } }); }
從上面代碼中,咱們很容易就看出,其實它就是這裏面封裝了一個okhttp3.Call,直接利用okhttp進行網絡的異步操做,至於okhttp是怎麼進行網絡請求的咱們就再也不這裏講解了,感興趣的朋友能夠本身去查看源碼。
好了,到這裏整個Retrofit的實現原理基本已解析完畢,相信你們學習過都可以很好的掌握了。ok,今天就講到這裏吧,原本還打算再寫個實例放上來的,看看篇幅也就放棄了,實戰部分會在下一篇和Rxjava一塊兒放出來,Rxjava我本身學習的都心花盛開了。看完記住關注微信平臺。
更多資訊請關注微信平臺,有博客更新會及時通知。愛學習愛技術。