由於以前Android開發第三方庫總結的文章在交流羣分享廣受好評,就有很多朋友讓我推薦對應的功能庫。想着,既然你們都以爲不錯,那也想着順手把本身經常使用的這些功能庫給整理出來,從此要是問我怎麼用,直接甩文章。哈哈哈,想一想都開心。java
本文面向對象:有必定基礎的Android開發者。android
本篇文章大體內容從以下三個方面講進行講解:git
固然,倘若各位以爲內容寫得很差,本人心態很差,不接受任何批評。仍是那句話:you can you up,no can no ……github
好了,話很少說,今天講Retrofit。小板凳拿好,開始上課。坐後面的朋友請到前面來。json
Retrofit,英文翻譯過來是翻新,改進的意思,光看名字很難聯想到他的具體做用,官方給的解釋是:Type-safe HTTP client for Android and Java by Square,翻譯過來就是由Square公司開發的一款針對Android網絡請求的框架,底層是基於OkHttp的。retrofit github地址api
在Android開發過程當中,有不少的網絡請求框架,好比Volley、Async Http Client,咱們爲何要用Retrofit?bash
爲何要用?一個詞描述:方便。使用方便,修改也方便。網絡
Retrofit的優勢:app
缺點:框架
當前文章編寫時最新版本爲2.6.1。導包時到github去導入最新版本便可。
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
複製代碼
Retrofit有一系列的輔助包,當咱們在導包的時候須要根據咱們的數據返回導入對應的包,不然會報異常: Could not locate ResponseBody converter for ……
好比咱們須要經過Gson轉對象,咱們須要增長以下Gson轉換輔助包:
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
複製代碼
若是咱們使用了protobuf格式,那咱們須要添加protobuf轉換輔助包:
implementation 'com.squareup.retrofit2:converter-protobuf:2.6.2'
複製代碼
固然,還有不少輔助包:好比guava,jackson,jaxb,moshi,scalars等一系列輔助包,固然,這些在retrofit的retrofit-converters包下都有,有興趣的能夠去深刻了解。這裏也列出來供你們導入。
Gson: compile 'com.squareup.retrofit2:converter-gson:2.6.2'
Jackson: compile 'com.squareup.retrofit2:converter-jackson:2.6.2'
Moshi: compile 'com.squareup.retrofit2:converter-moshi:2.6.2'
Protobuf: compile 'com.squareup.retrofit2:converter-protobuf:2.6.2'
Wire: compile 'com.squareup.retrofit2:converter-wire:2.6.2'
Simple XML: compile 'com.squareup.retrofit2:converter-simplexml:2.6.2'
Scalars (primitives, boxed, and String): compile 'com.squareup.retrofit2:converter-scalars:2.6.2'
複製代碼
導完包以後,我們記得在AndroidManifest.xml中聲明網絡請求權限,添加以下代碼便可申請網絡請求權限。
<uses-permission android:name="android.permission.INTERNET" />
複製代碼
好了,準備工做作完了,開始講使用步驟吧。
這裏咱們直接用官方給的例子來作示範:
public interface IGitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
複製代碼
public class Repo {
……//其餘屬性
private String name;
public String getName() {
return name;
}
}
複製代碼
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
IGitHubService service = retrofit.create(IGitHubService.class);
Call<List<Repo>> listRepos = service.listRepos("aserbao");
複製代碼
listRepos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
updateUi(response.body());//返回處理
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
複製代碼
固然,有一些特殊狀況,這裏也提一下:
當建立裝換對象中的字符不能使用時,咱們可使用annotations註解來解決這個問題。舉一個例子:json返回字段中若返回private屬性,衆所周知private不能在Android中當屬性名,那這時候怎麼辦呢?能夠這樣作:
@com.google.gson.annotations.SerializedName("private")
private boolean privateX;
複製代碼
好了,接下來介紹下Api的使用吧,Api的使用官方介紹也挺詳細的,這裏就做下簡單介紹。
上面使用案例中咱們用了兩個註解,分別是@GET和@Path,他們的做用是什麼呢?是否有其餘註解,接下來我們一塊兒去了解下Retrofit中的諸多註解以及他們的做用。
第一類:網絡請求註解
用於網絡請求方式的註解,好比@GET註解的就是經過get請求接口,@Post註解標記的就是經過post請求接口。相似的是還有@PUT、@DELETE、@HEAD(經常使用)。做用相同。很少敘述。
固然,在網絡請求註解中有一個特殊註解:@HTTP,這個註解相似於一個融合器,他能夠在使用上述請求的同時,並進行擴展配置。好比咱們經過@HTTP配置一個Get請求,且配置body,那咱們能夠這樣配置:
@HTTP(method = "GET",path = "{user}/repos", hasBody = true)
Call<List<Repo>> listRepos3(@Path("user") String user);
複製代碼
固然,若是不知道如何使用,直接點到HTTP接口的源碼中查看,註釋裏面便有具體使用案例。
第二類:網絡請求標記註解 retrofit中的標記註解有是三個,分別是:@FormUrlEncoded、@Multipart、@Streaming,見名知意,我們也稍微解釋下做用。
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
複製代碼
@POST("/file")
@Multipart
Observable<DataResponse<UploadBean>> uploadFile(@Part("file\"; filename=\"aserbao.png\"") RequestBody file,@Part("name") RequestBody nickName);
複製代碼
固然,@Multipart還能夠經過@PartMap添加多個上傳信息來實現一次上傳多個文件。好比咱們須要上傳aserbao/imgs這個目錄下的全部圖片,咱們能夠這樣實現。
@Multipart
@POST("/files")
Call<UploadBean> uploadFiles(@PartMap Map<String, RequestBody> params);
String aserbao_path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aserbao/imgs/";
File file1 = new File(aserbao_path);
if (!file1.exists()) return;
Map<String, RequestBody> partMap = new HashMap<>();
for (File file : file1) {
RequestBody fileBody = RequestBody.create(MediaType.parse("image/*"), file);
partMap.put("file\"; filename=\"" + file.getName() + "\"", fileBody);
}
……
複製代碼
第三類:網絡請求參數註解
這類註解也是使用最多的一類,下面我們來一塊兒瞭解下:
//@Header做用在參數上
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
//@Headers做用在方法上
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
//@HeaderMap經過鍵值對的方式給參數添加請求頭
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
複製代碼
@POST("users/new")
Call<User> createUser(@Body User user);
複製代碼
值得注意的是,當沒有添加轉換器的使用,@Body註釋的對象只能是RequestBody。
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
複製代碼
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
複製代碼
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
複製代碼
這裏當咱們調用方法listRepos("aserbao")時,對應@GET中的values值就會變成users/aserbao/repos
@GET("/user/test")
Call<Test> testQuery(@Query("id") String id);
複製代碼
調用testQuery(15),對應生成@GET中的values就是/user/test?id=15
@GET("https://api.github.com/users/aserbao/repos")
Call<List<Repo>> listAbsRepos();
@GET
Call<List<Repo>> listAbsRepos(@Url String url);
複製代碼
Retfoit的註解有一個value的參數,好比@GET("users/{user}/repos")。固然不一樣的baseUrl配置,value參數起的做用也是不一樣的。
繼續拿上面例子來講,好比咱們要請求https://api.github.com/users/aserbao/repos這個url,咱們能夠怎麼配置呢?
第一種:baseUrl中只添加host也就是https://api.github.com/,後面的參數寫在@GET註解裏。
這裏直接拿上面的例子中的代碼就能夠了。
new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build()
.create(IGitHubService.class)
.listRepos("aserbao");
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
複製代碼
第二種:咱們在baseUrl中添加https://api.github.com/users/,後面的參數添加到values裏面也能夠。
new Retrofit.Builder()
.baseUrl("https://api.github.com/users/") //這裏注意最後有添加/。
.build()
.create(IGitHubService.class)
.listRepos("aserbao");
@GET("{user}/repos")
Call<List<Repo>> listRepos2(@Path("user") String user);
複製代碼
第三種:咱們能夠直接將請求連接放到參數裏面。,
new Retrofit.Builder()
.baseUrl("")//baseUrl裏面能夠填空
.build()
.create(IGitHubService.class)
.listAbsRepos();
@GET("https://api.github.com/users/aserbao/repos")
Call<List<Repo>> listAbsRepos();
複製代碼
上面三種狀況,在實際項目開發過程當中咱們使用的較多的仍是第一種。
特別注意:baseUrl中添加的連接最後必需要添加/符號,不然會報java.lang.IllegalArgumentException: baseUrl must end in / 的異常。
在請求的時候給設置請求攔截器是頗有必要的一步,不只可讓咱們清楚的瞭解請求內容,快速定位請求過程當中遇到的問題。還能夠經過攔截請求添加通用參數和頭部字段。
那如何給Retrofit設置請求攔截器呢?前面也說了Retofit實際上市Okhttp的高度封裝,Okhttp如何設置,Retrofit就怎麼配置便可。固然,有興趣想了解更多關於Okhttp的內容能夠參考個人另一篇文章HTTP 網絡請求庫 OkHttp 的全面講解。
好了,話很少說,我們來看Retrofit如何設置攔截器。
步驟以下:
class LoggingInterceptor implements Interceptor {
@Override public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Log.e(TAG, String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
okhttp3.Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.e(TAG, String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
複製代碼
OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS)
//添加OkHttp3的攔截器
.addInterceptor(new LoggingInterceptor())
.writeTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS)
.build();
複製代碼
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.baseUrl("https://api.github.com/users")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)//配置OkHttpClient
.build();
複製代碼
經過上面的列子,咱們來看下請求運行後的攔截效果:
11-24 10:05:12.023 4671-4690/com.example.baseandroidframework E/RetrofitActivity: Received response for https://api.github.com/users/aserbao/repos in 2495.2ms
Date: Tue, 26 Nov 2019 01:36:31 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Server: GitHub.com
Status: 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1574735790
Cache-Control: public, max-age=60, s-maxage=60
Vary: Accept
ETag: W/"58bffa073ed17b36ffb324dd04f66539"
X-GitHub-Media-Type: github.v3; format=json
Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Content-Security-Policy: default-src 'none'
Vary: Accept-Encoding
X-GitHub-Request-Id: D99C:7F00:4DADB:61266:5DDC819D
複製代碼
好了,大功告成,咱們配置攔截器就這樣完成了。
到這裏,咱們的Retrofit的知識點算告一段落了,下面簡單總結下
首先和你們一塊兒來回顧下這篇文章的大體內容,主要講了關於Retrofit的三個方面的內容,分別是:
其實經過文章咱們能夠發現RetrofitAPI並很少,正如官方所言,他是一個關於OkHttp的高度封裝庫。
好了,文章到這裏就要結束了,若是對本文有什麼疑問或者不理解的地方,歡迎給我留言。固然,若是想系統性學Android,提高Android技術的朋友,能夠關注個人我的公衆號「aserbaocool」,加羣討論,一塊兒學習交流Android。