Retrofit2.0使用詳解

yangxi_001發表於2016-11-28

綜述

  retrofit是由square公司開發的。square在github上釋出了很多優秀的Android開源專案。例如:otto(事件匯流排),leakcanary(排查記憶體洩露),android-times-square(日曆控制元件),dagger(依賴注入),picasso(非同步載入圖片),okhttp(網路請求),retrofit(網路請求)等等。更多square上的開源專案我們可以去square的GitHub進行檢視。這次就來介紹一下retrofit的一些基本用法。retrofit是REST安卓客戶端請求庫。使用retrofit可以進行GET,POST,PUT,DELETE等請求方式。下面就來看一下retrofit的基本用法。

Retrofit使用方法

  由於retrofit2.0與先前版本的差別還是比較大,對於不同版本之間的差異在這裡就不在進行詳細區別。下面的例子也是針對於retrofit2.0進行介紹的。retrofit2.0它依賴於OkHttp,而且這部分也不再支援替換。在這裡我們也不需要顯示的匯入okHttp,在retrofit中已經匯入okhttp3。

<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>mockwebserver</artifactId>
  <scope>test</scope>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

  在下面的例子當中採用與GitHub一些相關api進行演示。在這裡首先需要新增訪問網路的許可權。

<uses-permission android:name="android.permission.INTERNET"/>
  • 1
  • 1

簡單示例

新增Gradle依賴項

  在這裡我們最好檢視一下retrofit的官網新增最新依賴。

compile 'com.squareup.retrofit2:retrofit:2.0.1'
  • 1
  • 1

建立API介面

  在retrofit中通過一個Java介面作為http請求的api介面。

public interface GitHubApi {

    @GET("repos/{owner}/{repo}/contributors")
    Call<ResponseBody> contributorsBySimpleGetCall(@Path("owner") String owner, @Path("repo") String repo);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

建立retrofit例項

  在這裡baseUrl是在建立retrofit實力的時候定義的,我們也可以在API介面中定義完整的url。在這裡建議在建立baseUrl中以”/”結尾,在API中不以”/”開頭和結尾。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

呼叫API介面

  在呼叫API介面請求後,獲得一個json字串,通過Gson進行解析,獲得login以及contributions。

GitHubApi repo = retrofit.create(GitHubApi.class);

    Call<ResponseBody> call = repo.contributorsBySimpleGetCall(mUserName, mRepo);
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            Gson gson = new Gson();
            ArrayList<Contributor> contributorsList = gson.fromJson(response.body().string(), new TypeToken<List<Contributor>>(){}.getType());
            for (Contributor contributor : contributorsList){
                Log.d("login",contributor.getLogin());
                Log.d("contributions",contributor.getContributions()+"");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

效果展示

  這樣就完成了一個http請求,上面請求的完整地址為:https://api.github.com/repos/square/retrofit/contributors 
  然後我們看一下執行結果: 
這裡寫圖片描述

取消請求

  我們可以終止一個請求。終止操作是對底層的httpclient執行cancel操作。即使是正在執行的請求,也能夠立即終止。

call.cancel();
  • 1
  • 1

轉換器

  在上面的例子中通過獲取ResponseBody後,我們自己使用Gson來解析接收到的Json格式資料。在Retrofit中當建立一個Retrofit例項的時候可以為其新增一個Json轉換器,這樣就會自動將Json格式的響應體轉換為所需要的Java物件。那麼先來看一下如何根據已有的Json格式資料如何生成Java物件。當然我們可以根據已知的資料手動建立Java物件,也可以通過工具更具Json格式為我們自動生成Java物件。

自動生成Java物件

  在這裡介紹兩種根據Json資料自動生成Java物件的工具。

jsonschema2pojo

  可以通過訪問jsonschema2pojo網站。先來看一下它的使用方法。 
這裡寫圖片描述
  上面配置中所選註解若是使用的Gson解析,可以選擇Gson,當然沒有也是可以的。對於@Generated註解若是需要保留的話新增如下依賴,也可以直接刪除@Generated註解,沒有任何影響。

compile 'org.glassfish:javax.annotation:10.0-b28'
  • 1
  • 1

GsonFormat

  GsonFormat是AndroidStudio中的一個外掛,在AndroidStudio的外掛選項中直接搜尋安裝這個外掛即可。在這裡看一下是如何使用這個外掛的。 
這裡寫圖片描述

新增轉換器

  在這裡我們需要為retrofit新增gson轉換器的依賴。新增過converter-gson後不用再新增gson庫。在converter-gson中已經包含gson。

compile 'com.squareup.retrofit2:converter-gson:2.0.1'
  • 1
  • 1

  在這裡先建立一個Java類Contributor,用來儲存接收到的資料。

public class Contributor {
    private String login;
    private Integer contributions;

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public Integer getContributions() {
        return contributions;
    }

    public void setContributions(Integer contributions) {
        this.contributions = contributions;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

  這時候修改我們的API介面。

@GET("repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributorsByAddConverterGetCall(@Path("owner") String owner, @Path("repo") String repo);
  • 1
  • 2
  • 1
  • 2

  建立retrofit例項,我們通過addConverterFactory指定一個factory來對響應反序列化,在這裡converters被新增的順序將是它們被Retrofit嘗試的順序。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

  呼叫上面所修改的API介面。

GitHubApi repo = retrofit.create(GitHubApi.class);
Call<List<Contributor>> call = repo.contributorsByAddConverterGetCall(mUserName, mRepo);
call.enqueue(new Callback<List<Contributor>>() {
    @Override
    public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
        List<Contributor> contributorList = response.body();
        for (Contributor contributor : contributorList){
            Log.d("login", contributor.getLogin());
            Log.d("contributions", contributor.getContributions() + "");
        }
    }

    @Override
    public void onFailure(Call<List<Contributor>> call, Throwable t) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

  最後在來看一下執行結果。 
這裡寫圖片描述
  retrofit不僅僅只支援gson,還支援其他許多json解析庫。以下版本號需要與retrofit版本號保持一致,並且以retrofit官網給出的版本號為準。

  • Gson:
    compile 'com.squareup.retrofit2:converter-gson:2.0.1'
  • Jackson:
    compile 'com.squareup.retrofit2:converter-jackson:2.0.1'
  • Moshi:
    compile 'com.squareup.retrofit2:converter-moshi:2.0.1'
  • Protobuf:
    compile 'com.squareup.retrofit2:converter-protobuf:2.0.1'
  • Wire:
    compile 'com.squareup.retrofit2:converter-wire:2.0.1'
  • Simple XML:
    compile 'com.squareup.retrofit2:converter-simplexml:2.0.1'
  • Scalars (primitives, boxed, and String):
    compile 'com.squareup.retrofit2:converter-scalars:2.0.1'

增加日誌資訊

  在retrofit2.0中是沒有日誌功能的。但是retrofit2.0中依賴OkHttp,所以也就能夠通過OkHttp中的interceptor來實現實際的底層的請求和響應日誌。在這裡我們需要修改上一個retrofit例項,為其自定自定義的OkHttpClient。程式碼如下:

HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(httpLoggingInterceptor)
        .build();

Retrofit retrofit = new Retrofit.Builder().addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .client(okHttpClient)
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

  還需要新增如下依賴。

compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
  • 1
  • 1

  其他程式碼沒有任何變化,我們來看一下執行結果。 
這裡寫圖片描述

新增請求頭

  我們可以通過@Headers來新增請求頭。

@Headers({
        "Accept: application/vnd.github.v3.full+json",
        "User-Agent: RetrofitBean-Sample-App",
        "name:ljd"
})
@GET("repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributorsAndAddHeader(@Path("owner") String owner,@Path("repo") String repo);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  執行結果。 
這裡寫圖片描述

同步請求

  在這裡我們可以直接通過call.execute()執行一個同步請求,由於不允許在主執行緒中進行網路請求操作,所以我們需要再子執行緒中進行執行。

new Thread(new Runnable() {
    @Override
    public void run() {

        try {
            Response<List<Contributor>> response = call.execute();
            List<Contributor> contributorsList = response.body();
            for (Contributor contributor : contributorsList){
                Log.d("login",contributor.getLogin());
                Log.d("contributions",contributor.getContributions()+"");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

  在這裡看一下執行結果。 
這裡寫圖片描述

clone

  在這裡無論是同步操作還是非同步操作每一個call物件例項只能被執行一次。多次執行丟擲如下異常。 
這裡寫圖片描述
  在這裡如果我們的request和respone都是一一對應的。我們通過Clone方法建立一個一模一樣的例項,並且它的開銷也是很小的。

Call<List<Contributor>> cloneCall = call.clone();
cloneCall.execute();
  • 1
  • 2
  • 1
  • 2

get請求

  在前面的一些例子當中我們都是採用get請求。當然我們也可以為URL指定查詢引數。使用@Query即可。

@GET("search/repositories")
Call<RetrofitBean> queryRetrofitByGetCall(@Query("q")String owner,
                                      @Query("since")String time,
                                      @Query("page")int page,
                                      @Query("per_page")int per_Page);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

  當我們的引數過多的時候我們可以通過@QueryMap註解和map物件引數來指定每個表單項的Key,value的值。

@GET("search/repositories")
Call<RetrofitBean> queryRetrofitByGetCallMap(@QueryMap Map<String,String> map);
  • 1
  • 2
  • 1
  • 2

  下面的call物件例項為上面api中所返回call物件。更具所返回的json資料所建立的實體類在這裡就不在貼出程式碼,下載原始碼詳細檢視。

call.enqueue(new Callback<RetrofitBean>() {
    @Override
    public void onResponse(Call<RetrofitBean> call, Response<RetrofitBean> response) {
        RetrofitBean retrofit = response.body();
        List<Item> list = retrofit.getItems();
        if (list == null)
            return;
        Log.d(TAG, "total:" + retrofit.getTotalCount());
        Log.d(TAG, "incompleteResults:" + retrofit.getIncompleteResults());
        Log.d(TAG, "----------------------");
        for (Item item : list) {
            Log.d(TAG, "name:" + item.getName());
            Log.d(TAG, "full_name:" + item.getFull_name());
            Log.d(TAG, "description:" + item.getDescription());
            Owner owner = item.getOwner();
            Log.d(TAG, "login:" + owner.getLogin());
            Log.d(TAG, "type:" + owner.getType());
        }

    }

    @Override
    public void onFailure(Call<RetrofitBean> call, Throwable t) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

  上面請求中的完整連線為: https://api.github.com/search/repositories?q=retrofit&since=2016-03-29&page=1&per_page=3,執行結果如下。 
這裡寫圖片描述

  在Retrofit 2.0新增了一個新的註解:@Url,它允許我們直接傳入一個請求的URL。這樣以來我們可以將上一個請求的獲得的url直接傳入進來。方便了我們的操作。

@GET
Call<List<Contributor>> repoContributorsPaginate(@Url String url);
  • 1
  • 2
  • 1
  • 2

Form encoded和Multipart

Form encoded

  我們可以使用@FormUrlEncoded註解來傳送表單資料。使用 @Field註解和引數來指定每個表單項的Key,value為引數的值。

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

  當我們有很多個表單引數時可以通過@FieldMap註解和Map物件引數來指定每個表單項的Key,value的值。

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@FieldMap Map<String,String> fieldMap);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Multipart

  我們還可以通過@Multipart註解來傳送Multipart資料。通過@Part註解來定義需要傳送的檔案。

@Multipart
@PUT("/user/photo")
User updateUser(@Part("photo") TypedFile photo, @Part("description") TypedString description);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Retrofit與RxJava結合

  Retrofit能夠與RxJava進行完美結合。下面就來看一下Retrofit與RxJava是如何結合在一起的。對於RxJava在這就不在進行詳細介紹,對於RXJava的使用可以參考附錄裡面給出連結。 
  首先我們需要新增如下依賴。

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.1'
compile 'io.reactivex:rxandroid:1.1.0'
  • 1
  • 2
  • 1
  • 2

  建立retrofit物件例項時,通過addCallAdapterFactory來新增對RxJava的支援。

HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(httpLoggingInterceptor)
        .build();
Retrofit retrofit = new Retrofit.Builder()
        .client(okHttpClient)
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("https://api.github.com/")
        .build();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

  使用Observable建立一個API介面。

@GET("repos/{owner}/{repo}/contributors")
Observable<List<Contributor>> contributorsByRxJava(@Path("owner") String owner,@Path("repo") String repo);
  • 1
  • 2
  • 1
  • 2

  下面來呼叫這個API介面。

private CompositeSubscription mSubscriptions = new CompositeSubscription();
  • 1
  • 1
mSubscriptions.add(
        mGitHubService.contributorsByRxJava(mUserName, mRepo)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<List<Contributor>>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onNext(List<Contributor> contributors) {
                        for (Contributor c : contributors) {
                            Log.d("TAG", "login:" + c.getLogin() + "  contributions:" + c.getContributions());
                        }
                    }
                }));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

  下面來看一下執行結果。 
這裡寫圖片描述
  如果我們想要檢視所有contributor的資訊,首先我們需要向gitHub請求獲取到所有contributor,然後再通過獲得contributor進行依次向github請求獲取contributor的資訊,在這時候我們使用RxJava也就非常方便了。下面看一下如何操作的。 
  首先再新增一個API介面。

@GET("repos/{owner}/{repo}/contributors")
Observable<List<Contributor>> contributorsByRxJava(@Path("owner") String owner,
                                                   @Path("repo") String repo);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

  下面在看一下是如何進行根據獲得的contributor來檢視contributor的資訊。

mSubscriptions.add(mGitHubService.contributorsByRxJava(mUserName, mRepo)
        .flatMap(new Func1<List<Contributor>, Observable<Contributor>>() {
            @Override
            public Observable<Contributor> call(List<Contributor> contributors) {
                return Observable.from(contributors);
            }
        })
        .flatMap(new Func1<Contributor, Observable<Pair<User, Contributor>>>() {
            @Override
            public Observable<Pair<User, Contributor>> call(Contributor contributor) {
                Observable<User> userObservable = mGitHubService.userByRxJava(contributor.getLogin())
                        .filter(new Func1<User, Boolean>() {
                            @Override
                            public Boolean call(User user) {
                                return !isEmpty(user.getName()) && !isEmpty(user.getEmail());
                            }
                        });

                return Observable.zip(userObservable,
                        Observable.just(contributor),
                        new Func2<User, Contributor, Pair<User, Contributor>>() {
                            @Override
                            public Pair<User, Contributor> call(User user, Contributor contributor) {
                                return new Pair<>(user, contributor);
                            }
                        });
            }
        })
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Pair<User, Contributor>>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Pair<User, Contributor> pair) {
                User user = pair.first;
                Contributor contributor = pair.second;
                Log.d(TAG, "name:" + user.getName());
                Log.d(TAG, "contributions:" + contributor.getContributions());
                Log.d(TAG, "email:" + user.getEmail());

            }
        }));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

  最後在來看下執行結果。 
這裡寫圖片描述

Retrofit設定快取

對Retrofit設定快取,由於Retrofit是對OkHttp的封裝,所以我們可以直接通過OkHttpClient著手。也就是為OkHttp設定快取。設定快取程式碼如下所示。

private OkHttpClient getCacheOkHttpClient(Context context){
    final File baseDir = context.getCacheDir();
    final File cacheDir = new File(baseDir, "HttpResponseCache");
    Timber.e(cacheDir.getAbsolutePath());
    Cache cache = new Cache(cacheDir, 10 * 1024 * 1024);   //快取可用大小為10M

    Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = chain -> {
        Request request = chain.request();
        if(!NetWorkUtils.isNetWorkAvailable(context)){
            request = request.newBuilder()
                    .cacheControl(CacheControl.FORCE_CACHE)
                    .build();
        }

        Response originalResponse = chain.proceed(request);
        if (NetWorkUtils.isNetWorkAvailable(context)) {
            int maxAge = 60;                  //線上快取一分鐘
            return originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .removeHeader("Cache-Control")
                    .header("Cache-Control", "public, max-age=" + maxAge)
                    .build();

        } else {
            int maxStale = 60 * 60 * 24 * 4 * 7;     //離線快取4周
            return originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .removeHeader("Cache-Control")
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .build();
        }
    };

    return new OkHttpClient.Builder()
            .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
            .addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
            .cache(cache)
            .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

總結

  在retrofit的使用中,對於檔案你上傳與下載,並沒有為我們提供進度更新的介面,在這裡就需要我們自己處理了。在下面的例子中給出一個檔案下載的例子,並且對下載進度更新通過logcat列印出來。可以下載進行檢視。到這裡retrofit的基本用法也就介紹完了,對於retrofit更多的好處在使用中我們可以慢慢體會。

原始碼下載

附錄