1. 程式人生 > >深度詳解Retrofit2使用(二)實踐

深度詳解Retrofit2使用(二)實踐

    深度詳解Retrofit2使用(一)基礎入門 這篇文章主要描述了Retrofit的註解,沒有涉及具體Retrofit的使用。今天就以Android為平臺,看看Retrofit是如何使用。

一. 準備

  1.1 匯入Retrofit庫。

上篇文章,我們提到過在Android中如何引入Retrofit庫。這裡在實際操作下,新建Android專案,在module的build.gradle檔案中,新增如下程式碼,

...  
    compile'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.1'
...
PS: 這裡和上篇文章描述不一樣,引入了兩個依賴,

1. compile'com.squareup.retrofit2:retrofit:2.0.2' ,是Retrofit依賴;

2. compile 'com.squareup.retrofit2:converter-gson:2.0.1' 是轉換gson的依賴。(預設請求下,Retrofit中的轉換物件是RequestBody、ResponseBody,而實際開發中,我們需要其他格式的資料,例如json格式、xml格式,這裡我需要轉換為json格式,所以就匯入這個庫)

加入上面的依賴程式碼後,點選同步,就會去下載他們相關聯的依賴庫。最後,我們切換到Project模式下,開啟External Libraries,可以看到如下的截圖,


可以看到,雖然我們只是添加了兩個依賴,但是實際上下載了5個庫(其他庫都是被依賴的),並且這裡是自動下載的。這裡確實比前面我們在java中手動下載爽啊!大笑

1.2 其他準備

  1. 新增網路許可權。因為我們的Android專案需要網路,所以,記得要新增網路許可權,

...
<uses-permission android:name="android.permission.INTERNET"/>
...
  2. 介面資料

因為需要一個服務端提供服務(介面資料),所以,就需要一個服務端。服務端有兩種實現方式,

1. 自己搭建服務端,搭建一個簡單的服務,具體的搭建可以參考java web開發(二) 介面開發

SpringMVC 開發介面;(有的朋友肯定會驚訝疑問,nima,使用Retrofit,還得自己先弄個服務,這代價有點大啊!週期太長了!但是,我想說,如果你對前端和後端都瞭解的話,那麼何愁找不到好工作呢!偷笑跑題了,脈動回來)

2. 使用現成的介面,目前市面上第三方提供的介面也較多,可以選擇使用。例如,https://api.github.com/

總之,在使用Retrofit前,請先準備好資料介面!

好了,經過上面的步驟,我們就可以開始使用Retrofit了!

二.使用 

2.1 介面資料

在使用介面資料前,我們先看看資料以及格式是什麼樣的。

在瀏覽器中輸入介面地址,例如地址是“http://192.168.21.163:8080/mServer/getStudent”,


上面是瀏覽器的截圖,可以看到該json資料的格式是,

{"code":" ","msg":" ","time":************,"items":[{},{}]}  

下面直接給出json資料格式設計。有三個類,

1. Response類 ,所有響應實體的基類,內部有三個欄位,code、msg、time。"code”是響應狀態碼,是標誌介面資料的狀態;"msg"是響應描述,是對“code”的文字描述;“time”是時間戳。所有的響應實體都應該繼承至該類。

2. EntityResponse,繼承至Response類,當介面響應資料中只有一個物件時,使用該類,多了一個屬性object。

3. ListResponse,繼承至Response類,當介面響應資料中返回一個數組時,使用該類,多了一個屬性是List。

下面是這幾個類的具體實現,

**
 *  基類
 */

public class Response implements Serializable {
    private String code;//響應狀態碼
    private String msg;//響應狀態描述
    private Long time = System.currentTimeMillis();//時間戳
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    @Override
    public String toString() {
        return "Response{" +
                "code='" + code + '\'' +
                ", msg='" + msg + '\'' +
                ", time=" + time +
                '}';
    }
}
/**
 * 單獨物件類
 */

public class EntityResponse<T> extends Response {

    private T object;// 返回一個物件的物件

    public T getObject() {
        return object;
    }

    public void setObject(T object) {
        this.object = object;
    }

    @Override
    public String toString() {
        return "EntityResponse{" +
                "object=" + object +
                '}';
    }
}
/**
 * 陣列實體類
 */

public class ListResponse<T> extends Response {
    private List<T> items;//返回一個數組

    public List<T> getItems() {
        return items;
    }

    public void setItems(List<T> items) {
        this.items = items;
    }

}
 下面開始使用Retrofit請求資料。(當點選按鈕時,從服務端獲取資料,解析後顯示)

2.2 GET請求

1.介面定義

public interface ApiService {

    @GET("StudentInq")
    Call<ListResponse<Student>> getStudents();

  
}
定義了一個介面,使用GET方式。

2.使用

...
   public void request() {
        // 1. 建立Retrofit物件
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2. 建立介面物件
        ApiService apiService = retrofit.create(ApiService.class);
        Call<ListResponse<Student>> call = apiService.getStudents();
        call.enqueue(new Callback<ListResponse<Student>>() {
            @Override
            public void onResponse(Call<ListResponse<Student>> call, Response<ListResponse<Student>> response) {
                if(response.isSuccessful()){
                   String code= response.body().getCode();
                   String msg= response.body().getMsg();
                    if (code != null
                            && code.equalsIgnoreCase("ok")) {
                        List<Student> list = response.body().getItems();
                        //獲取介面返回的列表資料
                        final StringBuffer sb = new StringBuffer();
                        for (Student student : list) {
                            sb.append("姓名:" + student.getName() + ", 年齡" + student.getAge() + ", 電話" + student.getMobile()).append("\n");
                        }
                        //更新UI,在子執行緒中,不能直接更新UI
                        tv.post(new Runnable() {
                            @Override
                            public void run() {
                                tv.setText(sb.toString());
                            }
                        });
                    }else{
                        Log.e("code---msg-->",code+","+msg);
                    }
                }else{
                    Log.e("response.code()----->",response.code()+"");
                }
            }

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

            }
        });
}
...
程式碼比較簡單!完成非同步呼叫,就可以獲取到介面資料了。具體程式碼請看文章末尾的DEMO例子。下面是在手機上的執行截圖,


上面的例子是一個GET請求。下面再看看POST請求,實際開發中會大量使用POST請求。

2.3 POST請求

1.介面定義

public interface ApiService {

    @GET("StudentInq")
    Call<ListResponse<Student>> getStudents();

    @FormUrlEncoded
    @POST("getStudent")
    Call<EntityResponse<Student>> getStudentById(@Field("id") int id);


 }
定義POST請求,並且設定了一個引數“id”,通過這個'id'獲取某個學生資訊。 一定要記得定義POST介面的規範!(使用表單提交POST,一定要@FormUrlEncoded、@Field和@POST配合使用)。

2.使用

...
    public void request() {
        // 1. 建立Retrofit物件
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2. 建立介面物件
        ApiService apiService = retrofit.create(ApiService.class);
        Call<EntityResponse<Student>> call = apiService.getStudentById(1);

        call.enqueue(new Callback<EntityResponse<Student>>() {
            @Override
            public void onResponse(Call<EntityResponse<Student>> call, Response<EntityResponse<Student>> response) {
                if (response.isSuccessful()) {
                    String code = response.body().getCode();
                    String msg = response.body().getMsg();
                    if (code != null
                            && code.equalsIgnoreCase("ok")) {
                        Student student = response.body().getObject();
                        //獲取介面返回的列表資料
                        final String text = "姓名:" + student.getName() + ", 年齡" + student.getAge() + ", 電話" + student.getMobile();
                        //更新UI,在子執行緒中,不能直接更新UI
                        tv.post(new Runnable() {
                            @Override
                            public void run() {
                                tv.setText(text);
                            }
                        });
                    } else {
                        Log.e("code---msg-->", code + "," + msg);
                    }
                } else {
                    Log.e("response.code()----->", response.code() + "");
                }
            }

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

            }
        });
...
上面網路請求的程式碼和GET請求都是一樣的。還是給張執行後的效果截圖,


  可以看到,使用Retrofit確實很方便、快捷。程式碼量也很少,效率高!

2.4 補充

 a. 介面定義

public interface ApiService {

  
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
}
 b. 使用
   public void request() {
        // 1. 建立Retrofit物件
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.API_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2. 建立介面物件
        ApiService apiService = retrofit.create(ApiService.class);
        Call<List<Contributor>> call = apiService.contributors("square", "retrofit");
        call.enqueue(new Callback<List<Contributor>>() {
            @Override
            public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
                List<Contributor> contributors = response.body();
                //                    //獲取介面返回的列表資料
                final StringBuffer sb = new StringBuffer();
                for (Contributor contributor : contributors) {
                    sb.append(contributor.getLogin() + " (" + contributor.getContributions() + ")").append("\n");;
                }
                //更新UI,在子執行緒中,不能直接更新UI
                tv.post(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText(sb.toString());
                    }
                });
            }

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

            }
        });

    }
看效果,


其實這個例項是Retrofit的github中的例子。
2. Retrofit結合Rxjava

  使用Rxjava前,需要先匯入其依賴。

...
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'io.reactivex.rxjava2:rxjava:2.1.5'
    compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
...
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1' ,使用Rxjava,需要引入兩個依賴庫

compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' ,銜接 Retrofit & RxJava

加入這幾行程式碼後,點選同步,稍等就可以了!

a. 介面定義

...
    @GET("StudentInq")
    Observable<ListResponse<Student>> getStudents();
...

只是將方法返回值型別更改了。之前是Call,現在是Observable(被觀察者)。

b. 請求
...

    public void request() {
        // 1. 建立Retrofit物件
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支援RxJava
                .build();
        // 2. 建立介面物件
        ApiService apiService = retrofit.create(ApiService.class);
        Observable<ListResponse<Student>> call = apiService.getStudents();
        call.subscribeOn(Schedulers.io()) // 在IO執行緒進行網路請求
                .observeOn(AndroidSchedulers.mainThread()) // 回到主執行緒 處理請求結果
                .subscribe(new Consumer<ListResponse<Student>>() {
            @Override
            public void accept(ListResponse<Student> studentListResponse) throws Exception {
                List<Student> list = studentListResponse.getItems();
                //獲取介面返回的列表資料
                final StringBuffer sb = new StringBuffer();
                for (Student student : list) {
                    sb.append("姓名:" + student.getName() + ", 年齡" + student.getAge() + ", 電話" + student.getMobile()).append("\n");
                }
                tv.setText(sb.toString());
            }
        });
}
...
執行效果就不截圖了!比較下來,Retrofit和Rxjava配合使用更加方便、高效!如虎添翼!偷笑
三.小結

  本文只是簡單的使用了幾個Retrofit的註解,其他很多註解都沒有講解。GET和POST,這兩種請求是比較常用的,尤其是POST在網路互動中大量使用,如果你對本文中的例子理解了,那麼就足夠了;至於其他的註解,在你需要使用的時候,即時查閱資料會使用就可以了。本文也簡單使用了Rxjava,相信大家也看到了Rxjava的強大,如果還未了解Rxjava,就趕緊動手吧!

 1.  可以看到,不管是GET請求還是POST請求,僅僅是在定義介面的地方不一樣,真正網路請求的地方,程式碼都是一樣的。

 2.  Retrofit和OkHttp有什麼區別呢?

    我們都知道OkHttp是目前使用頻率最多的網路請求庫,它的功能相當強大,它是Square公司的開源庫。而Retrofit呢,它也是Square公司的開源庫,並且Retrofit的網路請求其實是由OkHttp完成的。雖然Retrofit的網路請求是OkHttp完成的,但是,我們在使用Retrofit的時候,根本就察覺不到;如果我們將之前的網路請求由OkHttp改為Retrofit,也是很easy的。Retrofit是對OkHttp的封裝,讓使用者更方便、快捷的實現網路請求。趕緊入手Retrofit吧!

  前面一直提到過,Retrofit是對OkHttp的封裝,那麼我們可以替換調預設的OkHttp嗎?相信聰明的你肯定已經猜到答案了!