1. 程式人生 > 其它 >手撕Retrofit原始碼設計(二)

手撕Retrofit原始碼設計(二)

技術標籤:androidjavaretrofitokhttp

上一篇中大致對比了okhttp和retrofit傳送請求的大致流程,瞭解okhttp的工作流程對掌握retrofit是非常重要的。本篇繼續講解retrofit的內部構成。retrofit使用Builder模式完成構建,通過Builder模式開發者可以配置常用的GsonConvertFactory完成json資料例項化,也可以新增RxJava2CallAdapterFactory進行自定義請求,最終這些額外的配置都被儲存在Retrofit的例項當中。下面先來看Retrofit的屬性都有哪些:

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> callAdapterFactories;
  final @Nullable Executor callbackExecutor;
  	···
  }

serviceMethodCache

serviceMethodCache是一個儲存ServiceMethod的map。ServiceMethod是一個非常重要的類,我們在介面中定義的每一個請求方法最終都會在執行時被解析,方法註解中的所有資訊都會被儲存在一個ServiceMethod物件中。當方法被呼叫時,retrofit通過動態代理拿到執行時Method物件,根據Method物件構建一個ServiceMethod物件,並呼叫ServiceMethod的invoke方法完成最終的請求。

callFactory

callFactory是Okhttp中定義的介面,並不是retrofit定義的。他的作用就是建立網路請求的真正的Call物件。通過引用介面,開發者就可以注入自己的預設實現,達到多型的效果。他有一個預設的實現類大家都不會陌生:OkHttpClient。上一篇中我們說過retrofit是通過okhttp完成的網路請求,實際的體現就是這裡。

package okhttp3;

public interface Call extends Cloneable {
 
 	···

  interface Factory {
		Call newCall(Request request);
	}
}


public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
   ···
}

baseUrl

這個類比較簡單,就是用來儲存baseUrl,不再多說。

converterFactories

Converter.Factory是retrofit中定義的類。我們知道在okhttp的回撥方法中,最終的返回值是一個固定的型別Response。通過response.body()方法可以獲取到ResponseBody物件進而通過responseBody.string()方法獲取body的實際內容,這些型別都是固定的需要我們自己對返回結果進行手動解析。

但是在retrofit中,在資料請求成功回撥後,retrofit會在converterFactories列表中根據介面中方法的返回值Call<T>的泛型T,選擇一個合適的轉化器工廠,自動進行型別轉化.

package retrofit2;

public interface Converter<F, T> {

	@Nullable
  	T convert(F value) throws IOException;
	
	
	abstract class Factory {
	
		 public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
	        Type type, Annotation[] annotations, Retrofit retrofit) {
	      return null;
	    }
	    
		···
	}
}

Converter.Factory有一個預設的實現類BuiltInConverters,在建立retrofit的時候會永遠把BuiltInConverters放在converterFactories列表的第一個。BuiltInConverters是 retrofit 提供的預設資料轉化器工廠,他的轉化只是將ResponseBody直接快取返回,並沒有其他額外的工作。所以如果在介面中定義的方法的返回值是Call<ResponseBody>的時候,這時候retrofit就會使用BuiltInConverters進行資料轉化。

如果我們又向retrofit中添加了GsonConvertFactory,此時介面中方法的返回值就可以寫成這樣Call<User>,這時泛型不再是ResponseBody而是User,retrofit就會選擇使用GsonConvertFactory進行資料轉化。然後在回撥中我們就可以直接獲取到User物件了。

callAdapterFactories

這裡retrofit使用介面卡模式對最原始的okhttp中的Call物件進行一層層的裝飾,每一層的包裝都可以完成一些自定義的對Okhttp的Call的操作,比例:執行緒切換。在構建ServiceMethod的時候,retrofit會根據介面中定義方法的返回值型別去callAdapterFactories中查詢符合要求的adapter工廠。

CallAdapter.Factory也是retrofit提供的一個抽象的工廠類。

package retrofit2;

public interface CallAdapter<R, T> {
	···
	abstract class Factory {
			···
   }
}

DefaultCallAdapterFactory是該類的預設實現,在構建retrofit時會自動新增到callAdapterFactories列表中。DefaultCallAdapterFactory只會處理介面中方法返回值為Call<T>的型別。所以在預設情況下我們必須將介面中方法的返回值定義為Call<T>型別,否則會丟擲異常。

如果我們又為retrofit添加了RxJava2CallAdapterFactory,那麼此時介面中定義的方法就可以返回Observable<T>了,然後我們就可以使用RXJava的方式進行請求。但是此時callAdapterFactories列表中只有DefaultCallAdapterFactory和RxJava2CallAdapterFactory兩個工廠,也就是說現在介面中方法可以接受的返回值有Call<T>和Observable<T>兩種型別。如果你寫一個String型別,那麼同樣會丟擲異常。

callbackExecutor

就是有個普通的執行緒池,他的預設實現是一個通過Handler在主執行緒執行的類,retrofit預設的執行緒排程就是通過這個執行緒池。

package retrofit2;

class Platform {
	static final class MainThreadExecutor implements Executor {
	      private final Handler handler = new Handler(Looper.getMainLooper());
	
	      @Override
	      public void execute(Runnable r) {
	        handler.post(r);
	      }
	}
}

總結

可以看到retrofit的設計處處都透露著設計模式和程式碼的基本原則。在retrofit中引用了三種抽象的工廠,開發人員可以注入自己的工廠實現。用裝飾器模式對okhttp的Call進行自定義的處理達到執行緒切換的效果、通過動態代理執行網路請求等等。本篇從整體介紹了retrofit內部成員的職責,下一篇中將開始系統的講解retrofit是如何傳送網路請求到資料解析的整個流程。