好用的網絡請求庫Retrofit2(入門及講解)

前言

首先,先給出官網:

GitHub-Retrofit
官網-Retrofit

其次,要吐槽一下官網首頁給出的例子。如果你照著例子改,會發現根本沒法運行,不是少包就是少關鍵語句。

相關內容可以參看我的另一篇文章: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)。

  1. 獨立的請求和響應模塊
  2. 從響應處理分離出請求創建
  3. 每個實例只能使用一次。
  4. Call可以被克隆。
  5. 支持同步和異步方法。
  6. 能夠被取消。

由于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:

 本文由用戶 PeaDeBeuzev 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!