深度詳解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了!
二.使用
在看這一部分前,建議先看看我之前的一篇文章,java web開發(三) 接口使用。
2.1 接口數據
在使用接口數據前,我們先看看數據以及格式是什麼樣的。
在瀏覽器中輸入接口地址,例如地址是“http://192.168.21.163:8080/mServer/getStudent”,
上面是瀏覽器的截圖,可以看到該json數據的格式是,
{"code":" ","msg":" ","time":************,"items":[{},{}]}
有關json數據格式在我的java web接口開發系列文章講到過,這裏就不再詳細說明了,請看java web開發(二) 接口開發和java web開發(三) 接口使用。
下面直接給出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 補充
1. 使用GET請求從https://api.github.com/獲取數據。
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嗎?相信聰明的你肯定已經猜到答案了!