轉載請注明:http://www.qinglinyi.com/posts/retrofit/
認識Retrofit2
*** A type-safe HTTP client for Android and Java ***
意思就是說Retrofit是一個Android和Java的類型安全的Http客戶端/請求工具。
對于Retrofit的詳細介紹我們可以通過官網了解。
Retrofit2 使用
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Response<List<Repo>> response) {
// do something
}
@Override
public void onFailure(Throwable t) {
// do something
}
});
或者這樣:
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
service.listRepos("octocat")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe();
** 注意:
** 詳細的使用,大家可以查看其它教程。
Retrofit2是怎么工作的
如上面的使用中我們可以看到:
- 通過Retrofit.Builder()創建Retrofit。
- 調用Retrofit的create()方法將生成接口GitHubService的實例。
- 調用GitHubService的listRepos()方法返
Call<List<Repo>>
。 - 執行
Call<List<Repo>>
的enqueue方法在回調中處理返回的List<Repo>
。
Retrofit2的主要成員
那么在了解Retrofit2到底是怎么工作的之前我們先認識一下Retrofit2的主要成員:
Call(接口)--向服務器發送請求并返回響應的調用
CallAdapter(接口)--Call的適配器,用來包裝轉換Call
CallBack(接口)--顧名思義Call的回調,Call執行時的回調
Converter(接口)--數據轉換器,將一個對象轉化另外一個對象
CallAdapter.Factory(接口)--CallAdapter的工廠,通過get方法獲取CallAdapter
-
Converter.Factory(抽象類) -- 數據轉換器Converter的工廠
- responseBodyConverter -- 將服務器返回的數據轉化ResponseBody。可以理解為數據解析的轉換器
- requestBodyConverter -- 將GitHubService.listRepos()中的Body,Part和PartMap注解轉換為RequestBody(OkHttp3),以便http請求的時候使用。
- stringConverter -- 將Field,FieldMap 值,Header,Path,Query,和QueryMap值轉化為String,以便http請求的時候使用。
MethodHandler -- 處理、執行GitHubService方法的類
RequestFactory -- 創建OkHttp請求的Request
RequestFactoryParser -- 解析GitHubService.listRepos()方法的注解和參數,生成RequestFactory。(會用到requestBodyConverter,stringConverter)
OkHttpCall -- 實現Call接口,獲取傳入的Call(代理Call,通過Retrofit.callFactory生成的)執行請求,獲取數據并使用responseConverter進行解析。
創建Retrofit
通過Retrofit.Builder創建Retrofit,先看看Retrofit.Builder都有什么。
Retrofit.Builder:
private okhttp3.Call.Factory callFactory; // okhttp3 的網絡請求Call
private BaseUrl baseUrl; // 網絡請求地址的基礎部分(公共部分),Retrofit會自動拼接成真正的請求地址
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor; // 回調的Executor
private boolean validateEagerly;// 若為真,會提交調用eagerlyValidateMethods方法,提前加載MethodHandler
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
通過build的方法,我可以知道Retrofit.Builder提供一個默認的OkHttpClient,一個默認的CallAdapterFactory。
默認Platform:
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapter.FACTORY;
}
Platform.get().defaultCallAdapterFactory(callbackExecutor)返回默認的CallAdapterFactory有兩種情況:
- callbackExecutor 為空的時候返回的是DefaultCallAdapter.FACTORY,這個DefaultCallAdapter.FACTORY返回一個DefaultCallAdapter,DefaultCallAdapter很簡單,沒做什么處理。
- callbackExecutor不為空的時候返回ExecutorCallAdapterFactory,這個Factory返回的CallAdapter是ExecutorCallbackCall,我們看看這個ExecutorCallbackCall的enqueue方法:
@Override public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancelation
callback.onFailure(new IOException("Canceled"));
} else {
callback.onResponse(response);
}
}
});
}
@Override public void onFailure(final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(t);
}
});
}
});
}
也很簡單,就是修飾了一下CallBack,用callbackExecutor執行真正的回調,這樣回調可以在線程中執行并使用callbackExecutor管理。
如果是Android的話:
static class Android extends Platform {
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor == null) {
callbackExecutor = new MainThreadExecutor();
}
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
也就是說如果在Android上使用的話,如果callbackExecutor為空會直接使用handler將回調返回到主線程(MainThread)。
當然,如果需要自己配置請求Client的話可以設置callFactory。
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient
.Builder()
.addInterceptor(logger).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.client(client)
.build();
使用自己的OkHttpClient,并為這個OkHttpClient設置一個日志工具。通過這種方式設置,整個項目可以共用一個OkHttpClient。
動態代理
GitHubService service = retrofit.create(GitHubService.class);
create方法傳入一個接口GitHubService,然后動態代理GitHubService。
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);
}
return loadMethodHandler(method).invoke(args);
}
});
}
主要是loadMethodHandler(method).invoke(args)。也就是說在調用service.listRepos方法的時候,會通過loadMethodHandler(method).invoke(args)來執行。那么看看loadMethodHandler做了什么:
MethodHandler loadMethodHandler(Method method) {
MethodHandler handler;
synchronized (methodHandlerCache) {
handler = methodHandlerCache.get(method);
if (handler == null) {
handler = MethodHandler.create(this, method);
methodHandlerCache.put(method, handler);
}
}
return handler;
}
創建MethodHandler并使用一個Map-methodHandlerCache來自緩存MethodHandler。看來剩下的事交給MethodHandler了。
MethodHandler
static MethodHandler create(Retrofit retrofit, Method method) {
CallAdapter<?> callAdapter = createCallAdapter(method, retrofit);
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw Utils.methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
Converter<ResponseBody, ?> responseConverter =
createResponseConverter(method, retrofit, responseType);
RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
return new MethodHandler(retrofit.callFactory(), requestFactory, callAdapter,
responseConverter);
}
Object invoke(Object... args) {
return callAdapter.adapt(
new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
}
invoke()方法,調用callAdapter.adapt的方法并傳入一個OkHttpCall。如果是默認的CallAdapter的話返回的就是一個OkHttpCall或者ExecutorCallAdapterFactory.ExecutorCallbackCall,也就是說listRepos("user")方法就返回Call<List<Repo>> 。所以說方法返回什么要看CallAdapter.adapt,如果要返回Observable<List<Repo>>就需要RxJavaCallAdapterFactory.create()的CallAdapter。
-
在介紹的主要成員的時候說過OkHttpCall,執行請求的類,那么執行請求之前呢。那就要看create方法,這個方法中拿到:
- CallAdapter--通過Retrofit類的callAdapter方法獲得。
- 拿到ResponseConverter--通過Retrofit類的createResponseConverter方法獲得。
- 獲得RequestFactory--通過RequestFactoryParser.parse方法獲得。這個parse方法會解析method也就是listRepos("user")方法的注解和參數,返回一個RequestFactory。
static RequestFactory parse(Method method, Type responseType, Retrofit retrofit) {
RequestFactoryParser parser = new RequestFactoryParser(method);
parser.parseMethodAnnotations(responseType);
parser.parseParameters(retrofit);
return parser.toRequestFactory(retrofit.baseUrl());
}
注:具體的解析就不展開了,主要是將注解和參數的值獲取放入RequestAction,RequestFactory會根據這些RequestAction和基本參數構建OkHttp使用的Request。
- 最后這些callFactory, requestFactory, responseConverter將傳入OkHttpCall
OkHttpCall
執行Http請求返回數據并解析成實體,在回調中返回。
-
請求:通過CallFactory(OkHttpClient)的newCall方法傳入一個Request(通過requestFactory.create(args)創建)執行。
okhttp3.Call rawCall = 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; }
-
解析:通過responseConverter.convert()方法解析
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ... 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; } }
總結
- Retrofit就是一個Http請求工具。
- Retrofit使用接口代替Java類。
- Retrofit通過動態代理,用MethodHandler完成接口方法。
- Retrofit的MethodHandler通過RequestFactoryParser.parse解析,獲得接口方法的參數和注解的值,傳入到OkHttpCall,OkHttpCall生成okhttp3.Call完成Http請求并使用Converter解析數據回調。
- Retrofit通過工廠設置CallAdapter和Converter,CallAdapter包裝轉換Call,Converter轉換(解析)服務器返回的數據、接口方法的注解參數。