好用的網絡請求庫Retrofit2(入門及講解)
前言
首先,先給出官網:
其次,要吐槽一下官網首頁給出的例子。如果你照著例子改,會發現根本沒法運行,不是少包就是少關鍵語句。
相關內容可以參看我的另一篇文章:Retrofit(2.0)入門小錯誤 – Could not locate ResponseBody xxx Tried: * retrofit.BuiltInConverters
小栗子(example)
無論如何咱們還是先跑起來一個小栗子吧。
首先,在gralde文件中引入后續要用到的庫。
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'</code></pre>
接下來跟著我一步兩步往下走。
創建服務類和Bean
public static class Contributor {
public final String login;
public final int contributions;
public Contributor(String login, int contributions) {
this.login = login;
this.contributions = contributions;
}
@Override
public String toString() {
return "Contributor{" +
"login='" + login + '\'' +
", contributions=" + contributions +
'}';
}
}
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
接下來創建Retrofit2的實例,并設置BaseUrl和Gson轉換。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient())
.build();
創建請求服務,并為網絡請求方法設置參數
GitHub gitHubService = retrofit.create(GitHub.class);
Call<List<Contributor>> call = gitHubService.contributors("square", "retrofit");
最后,請求網絡,并獲取響應
try{
Response<List<Contributor>> response = call.execute(); // 同步
Log.d(TAG, "response:" + response.body().toString());
} catch (IOException e) {
e.printStackTrace();
}
Call是Retrofit中重要的一個概念,代表被封裝成單個請求/響應的交互行為
通過調用Retrofit2的execute(同步)或者enqueue(異步)方法,發送請求到網絡服務器,并返回一個響應(Response)。
- 獨立的請求和響應模塊
- 從響應處理分離出請求創建
- 每個實例只能使用一次。
- Call可以被克隆。
- 支持同步和異步方法。
- 能夠被取消。
由于call只能被執行一次,所以按照上面的順序執行會得到如下錯誤。
java.lang.IllegalStateException: Already executed
我們可以通過clone,來克隆一份call,從新調用。
// clone
Call<List<Contributor>> call1 = call.clone();
// 5. 請求網絡,異步
call1.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Response<List<Contributor>> response, Retrofit retrofit) {
Log.d(TAG, "response:" + response.body().toString());
}
@Override
public void onFailure(Throwable t) {
}
});</code></pre>
參數相關
網絡訪問肯定要涉及到參數請求,Retrofit為我們提供了各式各樣的組合方法。下面以標題+小例子的方式給出講解。
固定查詢參數
// 服務
interface SomeService {
@GET("/some/endpoint?fixed=query")
Call<SomeResponse> someEndpoint();
}
// 方法調用
someService.someEndpoint();
// 請求頭
// GET /some/endpoint?fixed=query HTTP/1.1</code></pre>
動態參數
// 服務
interface SomeService {
@GET("/some/endpoint")
Call<SomeResponse> someEndpoint(
@Query("dynamic") String dynamic);
}
// 方法調用
someService.someEndpoint("query");
// 請求頭
// GET /some/endpoint?dynamic=query HTTP/1.1</code></pre>
動態參數(Map)
// 服務
interface SomeService {
@GET("/some/endpoint")
Call<SomeResponse> someEndpoint(
@QueryMap Map<String, String> dynamic);
}
// 方法調用
someService.someEndpoint(
Collections.singletonMap("dynamic", "query"));
// 請求頭
// GET /some/endpoint?dynamic=query HTTP/1.1</code></pre>
省略動態參數
interface SomeService {
@GET("/some/endpoint")
Call<SomeResponse> someEndpoint(
@Query("dynamic") String dynamic);
}
// 方法調用
someService.someEndpoint(null);
// 請求頭
// GET /some/endpoint HTTP/1.1</code></pre>
固定+動態參數
interface SomeService {
@GET("/some/endpoint?fixed=query")
Call<SomeResponse> someEndpoint(
@Query("dynamic") String dynamic);
}
// 方法調用
someService.someEndpoint("query");
// 請求頭
// GET /some/endpoint?fixed=query&dynamic=query HTTP/1.1</code></pre>
路徑替換
interface SomeService {
@GET("/some/endpoint/{thing}")
Call<SomeResponse> someEndpoint(
@Path("thing") String thing);
}
someService.someEndpoint("bar");
// GET /some/endpoint/bar HTTP/1.1</code></pre>
固定頭
interface SomeService {
@GET("/some/endpoint")
@Headers("Accept-Encoding: application/json")
Call<SomeResponse> someEndpoint();
}
someService.someEndpoint();
// GET /some/endpoint HTTP/1.1
// Accept-Encoding: application/json</code></pre>
動態頭
interface SomeService {
@GET("/some/endpoint")
Call<SomeResponse> someEndpoint(
@Header("Location") String location);
}
someService.someEndpoint("Droidcon NYC 2015");
// GET /some/endpoint HTTP/1.1
// Location: Droidcon NYC 2015</code></pre>
固定+動態頭
interface SomeService {
@GET("/some/endpoint")
@Headers("Accept-Encoding: application/json")
Call<SomeResponse> someEndpoint(
@Header("Location") String location);
}
someService.someEndpoint("Droidcon NYC 2015");
// GET /some/endpoint HTTP/1.1
// Accept-Encoding: application/json
// Location: Droidcon NYC 2015</code></pre>
Post請求,無Body
interface SomeService {
@POST("/some/endpoint")
Call<SomeResponse> someEndpoint();
}
someService.someEndpoint();
// POST /some/endpoint?fixed=query HTTP/1.1
// Content-Length: 0</code></pre>
Post請求有Body
interface SomeService {
@POST("/some/endpoint")
Call<SomeResponse> someEndpoint(
@Body SomeRequest body);
}
someService.someEndpoint();
// POST /some/endpoint HTTP/1.1
// Content-Length: 3
// Content-Type: greeting
//
// Hi!</code></pre>
表單編碼字段
interface SomeService {
@FormUrlEncoded
@POST("/some/endpoint")
Call<SomeResponse> someEndpoint(
@Field("name1") String name1,
@Field("name2") String name2);
}
someService.someEndpoint("value1", "value2");
// POST /some/endpoint HTTP/1.1
// Content-Length: 25
// Content-Type: application/x-www-form-urlencoded
//
// name1=value1&name2=value2</code></pre>
表單編碼字段(Map)
interface SomeService {
@FormUrlEncoded
@POST("/some/endpoint")
Call<SomeResponse> someEndpoint(
@FieldMap Map<String, String> names);
}
someService.someEndpoint(
// ImmutableMap是OKHttp中的工具類
ImmutableMap.of("name1", "value1", "name2", "value2"));
// POST /some/endpoint HTTP/1.1
// Content-Length: 25
// Content-Type: application/x-www-form-urlencoded
//
// name1=value1&name2=value2</code></pre>
動態Url(Dynamic URL parameter)
interface GitHubService {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> repoContributors(
@Path("owner") String owner,
@Path("repo") String repo);
@GET
Call<List<Contributor>> repoContributorsPaginate(
@Url String url);
}
// 調用
Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");
Response<List<Contributor>> response = call.execute();
// 響應結果
// HTTP/1.1 200 OK
// Link: <https://api.github.com/repositories/892275/contributors?
page=2>; rel="next", <https://api.github.com/repositories/892275/
contributors?page=3>; rel="last"
// 獲取到頭中的數據
String links = response.headers().get("Link");
String nextLink = nextFromGitHubLinks(links);
// https://api.github.com/repositories/892275/contributors?page=2</code></pre>
可插拔的執行機制(Multiple, pluggable execution mechanisms)
interface GitHubService {
@GET("/repos/{owner}/{repo}/contributors")
// Call 代表的是CallBack回調機制
Call<List<Contributor>> repoContributors(
@Path("owner") String owner,
@Path("repo") String repo);
@GET("/repos/{owner}/{repo}/contributors")
// Observable 代表的是RxJava的執行
Observable<List<Contributor>> repoContributors2(
@Path("owner") String owner,
@Path("repo") String repo);
@GET("/repos/{owner}/{repo}/contributors")
Future<List<Contributor>> repoContributors3(
@Path("owner") String owner,
@Path("repo") String repo);
}</code></pre>
注意,要在構建Retrofit時指定適配器模式為RxJavaCallAdapterFactory
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl("http://www.duitang.com")
.build();
否則,會報出如下錯誤:
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable<com.bzh.sampleretrofit.ClubBean>. Tried:
- retrofit.ExecutorCallAdapterFactory</code></pre>
Retrofit執行模式




最后
授人以魚不如授人以漁 這是出自官方開發人員的講解的網站(自備梯子)
Retrofit作為一個上層框架,自然有很多底層lib庫支持,okio
和okhttp
都包含其中。
