標籤:
前言
時至今日,Android的網路架構不再像之前那麼到處都是,隨著Google把 HttpClient直接刪掉,似乎意味著Android越來越成熟。網路架構中的佼佼者Volley也不再那麼光鮮,取而代之的是 Retrofit 和 okHttp。
感覺很像 OnePiece 中白鬍子的離去象徵著時代的變革,新時代的開始,多弗的垮台象徵著七武海制度的取締一樣,不會使用Retrofit + okHttp + RxJava等一系列技術,就邁不進新時代的門檻,也不足以稱為一個合格的開發人員。
哈哈閑話不多說了,只是在 Android這個平台上 開發這麼長時間的一點感觸。各位看看笑笑也就算了。還是來介紹 Retrofit 吧。(直接略過1.9)
本文的所有代碼在 retrofitLearn;
1. Retrofit介紹
A type-safe HTTP client for Android and Java
一個用於Android和Java平台的型別安全的網路架構
Retrofit is a type-safe REST client for Android built by Square. The library provides a powerful framework for authenticating and interacting with APIs and sending network requests with OkHttp.
Retrofit 是一個Square開發的型別安全的REST安卓用戶端請求庫。這個庫為網路認證、API請求以及用OkHttp發送網路請求提供了強大的架構 。
Retrofit 把REST API返回的資料轉化為Java對象,就像ORM架構那樣,把資料庫內的儲存的資料轉化為相應的Java bean對象。
那麼我們知道Retrofit是一個型別安全的網路架構,而且它是使用REST API的,接下來我們看看什麼是REST吧。
2. REST 介紹:
Resources Representational State Transfer
資源表現層狀態轉化
- 每一個URI代表一種資源
- 用戶端和伺服器之間,傳遞這種資源的某種 表現層(“資源”具體呈現出來的形式,比如.txt,.png,.jpg)
- 用戶端通過四個HTTP動詞(GET用來擷取資源,POST用來建立或更新資源,PUT用來更新資源,DELETE用來刪除資源)對伺服器端資源進行操作,實現”表現層狀態轉化”
關於REST,這裡只僅僅列出了結論,文末有超級好的連結,請查看。如果你所使用的API是REST的,那麼恭喜你,這樣的API看起來真的很舒服,慶幸的是我司就使用的是REST API。
知道了REST是什麼,那接下啦就開始介紹Retrofit的用法啦。
3. Retrofit基本用法(未封裝)
1.在build.gradle中添加依賴
//okHttpcompile ‘com.squareup.okhttp3:okhttp:3.2.0‘//retrofitcompile ‘com.squareup.retrofit2:retrofit:2.0.2‘compile ‘com.squareup.retrofit2:converter-gson:2.0.2‘compile ‘com.squareup.okhttp3:logging-interceptor:3.2.0‘
2.建立介面,聲明API
//Retrofit turns your HTTP API into a Java interface.//建立介面,聲明GitHub的APIpublic interface GitHubAPI { /* 請求該介面:https://api.github.com/users/baiiu */ @GET("users/{user}") Call<User> userInfo(@Path("user") String user);}
3.在MainActivity.onCreate()方法中調用
/*1.初始化OkHttpClient*/OkHttpClient client = new OkHttpClient();/*2.建立Retrofit*/retrofit = new Retrofit.Builder() //設定OKHttpClient .client(client) //設定baseUrl,注意,baseUrl必須尾碼"/" .baseUrl("https://api.github.com/") //添加Gson轉換器 .addConverterFactory(GsonConverterFactory.create()) .build();/*2.擷取GitHub的API*/GitHubAPI gitHubAPI = retrofit.create(GitHubAPI.class);/*3.非同步呼叫*/Call<User> userCall = gitHubAPI.userInfo("baiiu");userCall.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { User body = response.body(); LogUtil.d(body == null ? "body == null" : body.toString()); } @Override public void onFailure(Call<User> call, Throwable t) { /* 判斷是否被cancel掉了 */ if (call.isCanceled()) { LogUtil.d("the call is canceled , " + toString()); } else { LogUtil.e(t.toString()); } } });/*取消調用*///userCall.cancel();/*同步調用,舉個例子,寫法如下(當然不能在主線程調用):*///Each instance can only be used once, but calling clone() will create a new instance that can be used.Call<User> clone = userCall.clone();Response<User> response = clone.execute();User body = response.body();LogUtil.d(body == null ? "body == null" : body.toString());
注意:
1. 設定BaseUrl時必須尾碼”/”,如 https://api.github.com/,這篇文章說的超清晰:Retrofit 2.0: The biggest update yet on the best HTTP Client Library for Android
2. 因為Retrofit在建立時候傳入了BaseUrl,所以基本上所有請求都基於該BaseUrl了。但是總有些API不是以該BaseUrl開頭的,特別是有些公司可能不是restful API的。那麼該怎麼辦呢。Retrofit提供了一個註解@Url解決這個問題,可以在運行時直接使用該Url直接存取。代碼如下:
//使用@Url註解,傳入該Url地址就OK啦,跨過BaseUrl,直接存取該Url地址@GET Call<Daily> getNewsList(@Url String url);
恩,接下來,知道了Retrofit的基本使用,接下來就是介紹Retrofit的註解了。
4. Retrofit註解
Retrofit使用註解來聲明API的請求方式、請求參數等。這裡只介紹一下它的 @Header 註解,其他的請閱讀 官網文檔 和 鴻洋的 Retrofit2 完全解析 探索與okhttp之間的關係。(這塊寫了也是翻譯官方文檔的和參考鴻樣的,會拉長篇幅)
要求標頭的設定可以通過 @Header 註解添加,又有兩種添加方式:
@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);
@GET("user")Call<User> getUser(@Header("Authorization") String authorization)
Note that headers do not overwrite each other. All headers with the same name will be included in the request.
同一個請求的同一個要求標頭在不同地方的設定不會被覆蓋,而是會被全部添加進要求標頭中。
Headers that need to be added to every request can be specified using an OkHttp interceptor.
如果要給每個請求都添加同樣的Header時,可以使用okHttp的 Interceptor 。
那麼,接下來就介紹Interceptor。
5.Interceptors使用
Retrofit 2.0 底層強制依賴okHttp,所以可以使用okHttp的攔截器Interceptors 來對所有請求進行再處理。
Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.
使用時,實現 Interceptor 介面,做我們自己的處理。
目前使用中,一般用來設定UA、設定緩衝策略 、列印Log 等。這裡介紹一個設定UA的Interceptor:
1.建立設定UA的Interceptor
public final class UserAgentInterceptor implements Interceptor { private static final String USER_AGENT_HEADER_NAME = "User-Agent"; private final String userAgentHeaderValue; public UserAgentInterceptor(String userAgentHeaderValue) { this.userAgentHeaderValue = userAgentHeaderValue; } @Override public Response intercept(Chain chain) throws IOException { final Request originalRequest = chain.request(); final Request requestWithUserAgent = originalRequest.newBuilder() //移除先前預設的UA .removeHeader(USER_AGENT_HEADER_NAME) //設定UA .addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue) .build(); return chain.proceed(requestWithUserAgent); }}
2.建立okHttpClient時 設定該Interceptor
okHttpClient = new OkHttpClient.Builder() //添加UA .addInterceptor(new UserAgentInterceptor(HttpHelper.getUserAgent())) //失敗重連 .retryOnConnectionFailure(true) //time out .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS) .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS) .build();
Interceptors 和 Header 的配合使用讓我們很方便的使用Http本身的緩衝。之前用Volley的時候這塊就比較難處理。解下來就說說Retrofit的緩衝機制。
6.
配置網路緩衝
使用Retrofit 感覺最方便的就是它提供的緩衝方式(雖然這是Http本身的),我們可以隨便通過Header和Interceptor配置自己的緩衝策略。
6.1 緩衝設定原理:
緩衝的設定是通過設定 Http要求標頭和回應標頭中的 Cache-Control 的 max-age 屬性達到的。在複寫 Interceptor 時,通過設定回應標頭的 Cache-Control 來達到目的。關於Http的本身的快取命中請查看文末連結 (畢竟Http也是個大傢伙) 。
6.2 緩衝設定步驟
設定緩衝目錄
retrofit本身預設無緩衝,連緩衝目錄都沒有提供預設的,所以 要想實現緩衝,必須要在建立OkHttpClient時設定緩衝目錄。 這塊超級坑,自己試了半天,最終看了下Cache那邊的源碼,竟然沒有預設的緩衝目錄!!!
設定緩衝的方式
- 通過添加
@Headers("Cache-Control: max-age=120") 進行設定。添加了Cache-Control 的請求,retrofit 會預設緩衝該請求的返回資料。
- 通過Interceptors實現緩衝。
6.3 實現Interceptor進行緩衝
提供了兩種緩衝策略(參考),設定緩衝時Application Interceptor 和 Net Interceptor 都要設定:
到現在為止,關於Retrofit的基本用法和緩衝設定已經瞭解了,寫點例子就已經會用了,接下來肯定就是進行封裝了,讓它更便於調用。
7. Retrofit 封裝
封裝Retrofit是為了提供更方便的調用,更好的配置和使用。那麼看到開頭的Retrofit調用方式,大概有這麼幾個步驟:
1. 建立OkHttpClient
2. 建立Retrofit執行個體
3. 擷取我們寫的API interface
4. 在代碼中非同步呼叫
那麼封裝時候也肯定從這幾步入手:
7.1
初始化OkHttpClient
建立OkHttpFactory類,初始化OkHttpClient並對外提供該執行個體的單例。並提供一個 HttpHelper 類用於提供所需要的參數,比如UA。
這樣做的好處是,程式中會使用OkHttp做一些其他請求操作,比如下載、上傳等網路操作,就可用共用一個OkHttpClient。
這裡使用枚舉產生單例。
enum OKHttpFactory { INSTANCE; private final OkHttpClient okHttpClient; private static final int TIMEOUT_READ = 25; private static final int TIMEOUT_CONNECTION = 25; OKHttpFactory() { //列印請求Log HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); //緩衝目錄 Cache cache = new Cache(MyApplication.mContext.getCacheDir(), 10 * 1024 * 1024); okHttpClient = new OkHttpClient.Builder() //列印請求log .addInterceptor(interceptor) //stetho,可以在chrome中查看請求 .addNetworkInterceptor(new StethoInterceptor()) //添加UA .addInterceptor(new UserAgentInterceptor(HttpHelper.getUserAgent())) //必須是設定Cache目錄 .cache(cache) //走緩衝,兩個都要設定 .addInterceptor(new OnOffLineCachedInterceptor()) .addNetworkInterceptor(new OnOffLineCachedInterceptor()) //失敗重連 .retryOnConnectionFailure(true) //time out .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS) .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS) .build(); } public OkHttpClient getOkHttpClient() { return okHttpClient; }}
7.2 初始化Retrofit
依然使用枚舉建立單例:
public enum RetrofitClient implements ApiContants { INSTANCE; private final Retrofit retrofit; RetrofitClient() { retrofit = new Retrofit.Builder() //設定OKHttpClient .client(OKHttpFactory.INSTANCE.getOkHttpClient()) //baseUrl .baseUrl(GITHUB_BASEURL) //gson轉化器 .addConverterFactory(GsonConverterFactory.create()) .build(); } public Retrofit getRetrofit() { return retrofit; }}
7.3 建立ApiFactory類封裝所有API
如題,建立ApiFactory類管理所有的API interface,對外提供方法擷取他們,這樣調用時會方便很多,而且也便於修改。
public enum ApiFactory { INSTANCE; private final GitHubAPI gitHubAPI; private final AnotherAPI anotherAPI; ApiFactory() { gitHubAPI = RetrofitClient.INSTANCE.getRetrofit().create(GitHubAPI.class); anotherAPI = RetrofitClient.INSTANCE.getRetrofit().create(AnotherAPI.class); } public GitHubAPI gitHubAPI() { return gitHubAPI; } public AnotherAPI getAnotherAPI() { return anotherAPI; }}
這樣封裝在外部調用時會方便很多,比如:
Call<User> userCall = ApiFactory.gitHubAPI().userInfo("baiiu");
封裝的代碼在GitHub上:retrofitLearn;
這樣封裝自己覺得還不錯,就可以開心的寫代碼啦。接下來說說一個神奇的工具。
8. Stetho 一個神奇的工具
首先:使用該工具需要翻牆。 不能翻牆的還是使用Charles吧。
- gradle中添加:
compile ‘com.facebook.stetho:stetho:1.3.1‘ compile ‘com.facebook.stetho:stetho-okhttp3:1.3.1‘
- 開啟chrome,輸入
chrome://inspect
點擊你的程式進行inspect,就可以直接使用Chrome進行抓包、調試你的應用啦。但是不能翻牆的話,你會看到一片空白。。。
結語:
畢竟Retrofit出來已經很久了,沒有的趕緊用用吧。在使用Retrofit時,深深趕緊到其對Http本身機制的應用之深,真的感覺到非常棒的應用體驗。用Retrofit作為網路架構,簡直就能感覺到它設計之美,更何況還能和RxJava結合起來,美到不行。
參考:這些參考都值得一看的
關於Retrofit的一本書
Retrofit — Basic Authentication on Android
retrofit介紹:
retrofit官網
Simple HTTP with Retrofit 2
Consuming APIs with Retrofit
Retrofit2 完全解析 探索與okhttp之間的關係
Retrofit 2.0: The biggest update yet on the best HTTP Client Library for Android
Restful API介紹
理解RESTful架構
深入淺出REST
OkHttp
effective okHttp
Android OkHttp完全解析 是時候來瞭解OkHttp了
Android 一個改善的okHttp封裝庫
Interceptors
wiki-Interceptors
wiki-Interceptors 中文
配置緩衝
Retrofit2.0+okHttp3緩衝機制以及遇到的問題
使用Retrofit和OkHttp實現網路緩衝。無網讀緩衝,有網根據到期時間重新請求
瀏覽器 HTTP 緩衝原理分析
瀏覽器緩衝
其他助於理解的
四種常見的 POST 提交資料方式
stetho
解決provisional headers are shown的過程
Android 網路架構 Retrofit2.0介紹、使用和封裝