1. 程式人生 > >Android RxJava操作符的學習---功能性操作符--(有條件)網路請求輪詢(結合Retrofit)

Android RxJava操作符的學習---功能性操作符--(有條件)網路請求輪詢(結合Retrofit)

1. 需求場景

 

2. 功能說明

採用Get方法對 金山詞霸API 按規定時間重複傳送網路請求,從而模擬 輪詢 需求實現

  1. 停止輪詢的條件 = 當輪詢到第4次時
  2. 採用 Gson 進行資料解析

 

3. 具體實現

下面,我將結合 RetrofitRxJava 實現 有條件的輪詢需求

3.1 步驟說明

  1. 新增依賴
  2. 建立 接收伺服器返回資料 的類
  3. 建立 用於描述網路請求 的介面(區別於Retrofit傳統形式)
  4. 建立 Retrofit 例項
  5. 建立 網路請求介面例項 並 配置網路請求引數(區別於Retrofit
    傳統形式)
  6. 傳送網路請求(區別於Retrofit傳統形式)
  7. 傳送網路請求
  8. 對返回的資料進行處理

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 的資料格式,建立 接收伺服器返回資料 的類:

Translation.java

public class Translation {

    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 {

    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20world")
    Observable<Translation> getCall();
     // 註解裡傳入 網路請求 的部分URL地址
    // Retrofit把網路請求的URL分成了兩部分:一部分放在Retrofit物件裡,另一部分放在網路請求接口裡
    // 如果接口裡的url是一個完整的網址,那麼放在Retrofit物件裡的URL可以忽略
    // 採用Observable<...>介面 
    // getCall()是接受網路請求資料的方法
}

接下來的步驟均在RxJavafixRxjava.java內實現(請看註釋)

RxJavafixRxjava.java

public class RxJavafixRetrofit extends AppCompatActivity {

    private static final String TAG = "Rxjava";

    // 設定變數 = 模擬輪詢伺服器次數
    private int i = 0 ;

    @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<...>形式 對 網路請求 進行封裝
                        Observable<Translation> observable = request.getCall();

                        // 步驟4:傳送網路請求 & 通過repeatWhen()進行輪詢
                        observable.repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
                            @Override
                            // 在Function函式中,必須對輸入的 Observable<Object>進行處理,此處使用flatMap操作符接收上游的資料
                            public ObservableSource<?> apply(@NonNull Observable<Object> objectObservable) throws Exception {
                                // 將原始 Observable 停止傳送事件的標識(Complete() /  Error())轉換成1個 Object 型別資料傳遞給1個新被觀察者(Observable)
                                // 以此決定是否重新訂閱 & 傳送原來的 Observable,即輪詢
                                // 此處有2種情況:
                                // 1. 若返回1個Complete() /  Error()事件,則不重新訂閱 & 傳送原來的 Observable,即輪詢結束
                                // 2. 若返回其餘事件,則重新訂閱 & 傳送原來的 Observable,即繼續輪詢
                                return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
                                    @Override
                                    public ObservableSource<?> apply(@NonNull Object throwable) throws Exception {

                                        // 加入判斷條件:當輪詢次數 = 5次後,就停止輪詢
                                        if (i > 3) {
                                            // 此處選擇傳送onError事件以結束輪詢,因為可觸發下游觀察者的onError()方法回撥
                                            return Observable.error(new Throwable("輪詢結束"));
                                        }
                                        // 若輪詢次數<4次,則傳送1Next事件以繼續輪詢
                                        // 注:此處加入了delay操作符,作用 = 延遲一段時間傳送(此處設定 = 2s),以實現輪詢間間隔設定
                                        return Observable.just(1).delay(2000, TimeUnit.MILLISECONDS);
                                    }
                                });

                            }
                        }).subscribeOn(Schedulers.io())               // 切換到IO執行緒進行網路請求
                                .observeOn(AndroidSchedulers.mainThread())  // 切換回到主執行緒 處理請求結果
                                .subscribe(new Observer<Translation>() {
                                    @Override
                                    public void onSubscribe(Disposable d) {
                                    }

                                    @Override
                                    public void onNext(Translation result) {
                                        // e.接收伺服器返回的資料
                                        result.show() ;
                                        i++;
                                    }

                                    @Override
                                    public void onError(Throwable e) {
                                        // 獲取輪詢結束資訊
                                        Log.d(TAG,  e.toString());
                                    }

                                    @Override
                                    public void onComplete() {

                                    }
                                });

                    }
    }

3.3 測試結果