Android RxJava 實戰系列:優雅實現 網路請求巢狀回撥
阿新 • • 發佈:2018-11-04
轉自-----http://blog.csdn.net/carson_ho/article/details/78315696,請為大神打call
前言
Rxjava
,由於其基於事件流的鏈式呼叫、邏輯簡潔 & 使用簡單的特點,深受各大Android
開發者的歡迎。
如果還不瞭解RxJava,請看文章:Android:這是一篇 清晰 & 易懂的Rxjava 入門教程
RxJava
如此受歡迎的原因,在於其提供了豐富 & 功能強大的操作符,幾乎能完成所有的功能需求- 今天,我將為大家帶來
Rxjava
Retrofit
與RxJava
實現,希望大家會喜歡。
- 本系列文章主要基於
Rxjava 2.0
- 接下來的時間,我將持續推出
Android
中Rxjava 2.0
的一系列文章,包括原理、操作符、應用場景、背壓等等 ,有興趣可以繼續關注Carson_Ho的安卓開發筆記!!
目錄
1. 需求場景
1.1 背景
需要進行巢狀網路請求:即在第1個網路請求成功後,繼續再進行一次網路請求
如 先進行 使用者註冊 的網路請求, 待註冊成功後回再繼續傳送 使用者登入 的網路請求
1.2 衝突
巢狀實現網路請求較為複雜,即巢狀呼叫函式
下面展示的是結合
Retrofit
與RxJava
的基本用法,即未用操作符前
// 傳送註冊網路請求的函式方法
private void register() {
api.register(new RegisterRequest())
.subscribeOn(Schedulers.io()) //在IO執行緒進行網路請求
.observeOn(AndroidSchedulers.mainThread()) //回到主執行緒去處理請求結果
.subscribe(new Consumer<RegisterResponse>() {
@Override
public void accept(RegisterResponse registerResponse) throws Exception {
Toast.makeText(MainActivity.this, "註冊成功", Toast.LENGTH_SHORT).show();
login(); //註冊成功, 呼叫登入的方法
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Toast.makeText(MainActivity.this, "註冊失敗", Toast.LENGTH_SHORT).show();
}
});
}
// 傳送登入網路請求的函式方法
private void login() {
api.login(new LoginRequest())
.subscribeOn(Schedulers.io()) //在IO執行緒進行網路請求
.observeOn(AndroidSchedulers.mainThread()) //回到主執行緒去處理請求結果
.subscribe(new Consumer<LoginResponse>() {
@Override
public void accept(LoginResponse loginResponse) throws Exception {
Toast.makeText(MainActivity.this, "登入成功", Toast.LENGTH_SHORT).show();
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Toast.makeText(MainActivity.this, "登入失敗", Toast.LENGTH_SHORT).show();
}
});
}
1.3 解決方案
結合 RxJava2
中的變換操作符FlatMap()
實現巢狀網路請求
關於該操作符的使用具體請看文章:Android RxJava:圖文詳解 變換操作符
2. 功能說明
-
實現功能:傳送巢狀網路請求(將英文翻譯成中文,翻譯兩次)
- 為了讓大家都能完成
Demo
,所以通過 公共的金山詞霸API 來模擬 “註冊 - 登入”巢狀網路請求 - 即先翻譯
Register
(註冊),再翻譯Login
(登入)
- 為了讓大家都能完成
-
實現方案:採用
Get
方法對 金山詞霸API 傳送網路請求採用
Gson
進行資料解析
3. 具體實現
下面我將結合 Retrofit
與RxJava
實現網路請求巢狀
3.1 步驟說明
- 新增依賴
- 建立 接收伺服器返回資料 的類
- 建立 用於描述網路請求 的介面(區別於
Retrofit
傳統形式) - 建立 Retrofit 例項
- 建立 網路請求介面例項 並 配置網路請求引數(區別於
Retrofit
傳統形式) - 傳送網路請求(區別於
Retrofit
傳統形式) - 傳送網路請求
- 對返回的資料進行處理
本例項側重於說明
RxJava
的執行緒控制,關於Retrofit
的使用請看文章:這是一份很詳細的 Retrofit 2.0 使用教程(含例項講解)
3.2 步驟實現
步驟1: 新增依賴
a. 在 Gradle
加入Retrofit
庫的依賴
build.gradle
dependencies {
// Android 支援 Rxjava
// 此處一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
// Android 支援 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
// 銜接 Retrofit & RxJava
// 此處一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
// 支援Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
}
b. 新增 網路許可權
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
步驟2:建立 接收伺服器返回資料 的類
- 金山詞霸
API
的資料格式說明如下:
// URL模板
http://fy.iciba.com/ajax.php
// URL例項
http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world
// 引數說明:
// a:固定值 fy
// f:原文內容型別,日語取 ja,中文取 zh,英語取 en,韓語取 ko,德語取 de,西班牙語取 es,法語取 fr,自動則取 auto
// t:譯文內容型別,日語取 ja,中文取 zh,英語取 en,韓語取 ko,德語取 de,西班牙語取 es,法語取 fr,自動則取 auto
// w:查詢內容
- 示例
- 根據 金山詞霸API 的資料格式,建立 接收伺服器返回資料 的類:
為了演示是2個網路請求,所以對應設定2個接收伺服器的資料類
<-- Translation1.java -->
public class Translation1 {
private int status;
private content content;
private static class content {
private String from;
private String to;
private String vendor;
private String out;
private int errNo;
}
//定義 輸出返回資料 的方法
public void show() {
Log.d("RxJava", "翻譯內容 = " + content.out);
}
}
<-- Translation2.java -->
public class Translation2 {
private int status;
private content content;
private static class content {
private String from;
private String to;
private String vendor;
private String out;
private int errNo;
}
//定義 輸出返回資料 的方法
public void show() {
Log.d("RxJava", "翻譯內容 = " + content.out);
}
}
步驟3:建立 用於描述網路請求 的介面
採用 註解 + Observable<...>
介面描述 網路請求引數
GetRequest_Interface.java
public interface GetRequest_Interface {
// 網路請求1
@GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20register")
Observable<Translation1> getCall();
// 網路請求2
@GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20login")
Observable<Translation2> getCall_2();
// 註解裡傳入 網路請求 的部分URL地址
// Retrofit把網路請求的URL分成了兩部分:一部分放在Retrofit物件裡,另一部分放在網路請求接口裡
// 如果接口裡的url是一個完整的網址,那麼放在Retrofit物件裡的URL可以忽略
// 採用Observable<...>介面
// getCall()是接受網路請求資料的方法
}
接下來的步驟均在MainActivity.java內實現(請看註釋)
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Rxjava";
// 定義Observable介面型別的網路請求物件
Observable<Translation1> observable1;
Observable<Translation2> observable2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 步驟1:建立Retrofit物件
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/") // 設定 網路請求 Url
.addConverterFactory(GsonConverterFactory.create()) //設定使用Gson解析(記得加入依賴)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支援RxJava
.build();
// 步驟2:建立 網路請求介面 的例項
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
// 步驟3:採用Observable<...>形式 對 2個網路請求 進行封裝
observable1 = request.getCall();
observable2 = request.getCall_2();
observable1.subscribeOn(Schedulers.io()) // (初始被觀察者)切換到IO執行緒進行網路請求1
.observeOn(AndroidSchedulers.mainThread()) // (新觀察者)切換到主執行緒 處理網路請求1的結果
.doOnNext(new Consumer<Translation1>() {
@Override
public void accept(Translation1 result) throws Exception {
Log.d(TAG, "第1次網路請求成功");
result.show();
// 對第1次網路請求返回的結果進行操作 = 顯示翻譯結果
}
})
.observeOn(Schedulers.io()) // (新被觀察者,同時也是新觀察者)切換到IO執行緒去發起登入請求
// 特別注意:因為flatMap是對初始被觀察者作變換,所以對於舊被觀察者,它是新觀察者,所以通過observeOn切換執行緒
// 但對於初始觀察者,它則是新的被觀察者
.flatMap(new Function<Translation1, ObservableSource<Translation2>>() { // 作變換,即作巢狀網路請求
@Override
public ObservableSource<Translation2> apply(Translation1 result) throws Exception {
// 將網路請求1轉換成網路請求2,即傳送網路請求2
return observable2;
}
})
.observeOn(AndroidSchedulers.mainThread()) // (初始觀察者)切換到主執行緒 處理網路請求2的結果
.subscribe(new Consumer<Translation2>() {
@Override
public void accept(Translation2 result) throws Exception {
Log.d(TAG, "第2次網路請求成功");
result.show();
// 對第2次網路請求返回的結果進行操作 = 顯示翻譯結果
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
System.out.println("登入失敗");
}
});
}
}
3.3 測試結果
4. Demo地址
Carson_Ho的Github地址 = RxJava2實戰系列:網路請求巢狀回撥
喜歡的麻煩點個
star
!
5. 總結
- 本文主要講解了
Rxjava
變換操作符的實際開發需求場景:巢狀回撥需求 ,並結合Retrofit
與RxJava
實現 - 接下來的時間,我將持續推出
Android
中Rxjava 2.0
的一系列文章,包括原理、操作符、應用場景、背壓等等 ,有興趣可以繼續關注Carson_Ho的安卓開發筆記!!