可能是東半球最全的RxJava使用場景小結

yangxi_001發表於2017-10-13

一、Scheduler執行緒切換

這種場景經常會在“後臺執行緒取資料,主執行緒展示”的模式中看見

[html] view plain copy
  1. Observable.just(1, 2, 3, 4)  
  2.             .subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 執行緒  
  3.             .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回撥發生在主執行緒  
  4.             .subscribe(new Action1<Integer>() {  
  5.         @Override  
  6.         public void call(Integer number) {  
  7.             Log.d(tag, "number:" + number);  
  8.         }  
  9.     });  

二、使用debounce做textSearch

用簡單的話講就是當N個結點發生的時間太靠近(即發生的時間差小於設定的值T),debounce就會自動過濾掉前N-1個結點。

比如在做百度地址聯想的時候,可以使用debounce減少頻繁的網路請求。避免每輸入(刪除)一個字就做一次聯想

[html] view plain copy
  1. RxTextView.textChangeEvents(inputEditText)  
  2.       .debounce(400, TimeUnit.MILLISECONDS)   
  3.       .observeOn(AndroidSchedulers.mainThread())  
  4.       .subscribe(new Observer<TextViewTextChangeEvent>() {  
  5.     @Override  
  6.     public void onCompleted() {  
  7.         log.d("onComplete");  
  8.     }  
  9.   
  10.     @Override  
  11.     public void onError(Throwable e) {  
  12.         log.d("Error");  
  13.     }  
  14.   
  15.     @Override  
  16.     public void onNext(TextViewTextChangeEvent onTextChangeEvent) {  
  17.         log.d(format("Searching for %s", onTextChangeEvent.text().toString()));  
  18.     }  
  19. });  

三、Retrofit結合RxJava做網路請求框架
這裡不作詳解,具體的介紹可以看扔物線的這篇文章,對RxJava的入門者有很大的啟發。其中也講到了RxJava和Retrofit如何結合來實現更簡潔的程式碼

四、RxJava代替EventBus進行資料傳遞:RxBus
注意:RxBus並不是一個庫,而是一種模式,是使用了RxJava的思想來達到EventBus的資料傳遞效果。這篇文章RxBus講的比較詳細。

五、使用combineLatest合併最近N個結點
例如:註冊的時候所有輸入資訊(郵箱、密碼、電話號碼等)合法才點亮註冊按鈕。
  1. Observable<CharSequence> _emailChangeObservable = RxTextView.textChanges(_email).skip(1);  
  2. Observable<CharSequence> _passwordChangeObservable = RxTextView.textChanges(_password).skip(1);  
  3. Observable<CharSequence>   _numberChangeObservable = RxTextView.textChanges(_number).skip(1);  
  4.   
  5. Observable.combineLatest(_emailChangeObservable,  
  6.               _passwordChangeObservable,  
  7.               _numberChangeObservable,  
  8.               new Func3<CharSequence, CharSequence, CharSequence, Boolean>() {  
  9.                   @Override  
  10.                   public Boolean call(CharSequence newEmail,  
  11.                                       CharSequence newPassword,  
  12.                                       CharSequence newNumber) {  
  13.   
  14.                       Log.d("xiayong",newEmail+" "+newPassword+" "+newNumber);  
  15.                       boolean emailValid = !isEmpty(newEmail) &&  
  16.                                            EMAIL_ADDRESS.matcher(newEmail).matches();  
  17.                       if (!emailValid) {  
  18.                           _email.setError("Invalid Email!");  
  19.                       }  
  20.   
  21.                       boolean passValid = !isEmpty(newPassword) && newPassword.length() > 8;  
  22.                       if (!passValid) {  
  23.                           _password.setError("Invalid Password!");  
  24.                       }  
  25.   
  26.                       boolean numValid = !isEmpty(newNumber);  
  27.                       if (numValid) {  
  28.                           int num = Integer.parseInt(newNumber.toString());  
  29.                           numValid = num > 0 && num <= 100;  
  30.                       }  
  31.                       if (!numValid) {  
  32.                           _number.setError("Invalid Number!");  
  33.                       }  
  34.   
  35.                       return emailValid && passValid && numValid;  
  36.   
  37.                   }  
  38.               })//  
  39.               .subscribe(new Observer<Boolean>() {  
  40.                   @Override  
  41.                   public void onCompleted() {  
  42.                       log.d("completed");  
  43.                   }  
  44.   
  45.                   @Override  
  46.                   public void onError(Throwable e) {  
  47.                      log.d("Error");  
  48.                   }  
  49.   
  50.                   @Override  
  51.                   public void onNext(Boolean formValid) {  
  52.                      _btnValidIndicator.setEnabled(formValid);    
  53.                   }  
  54.               });  

六、使用merge合併兩個資料來源。

例如一組資料來自網路,一組資料來自檔案,需要合併兩組資料一起展示。

  1. Observable.merge(getDataFromFile(), getDataFromNet())  
  2.               .observeOn(AndroidSchedulers.mainThread())  
  3.               .subscribe(new Subscriber<String>() {  
  4.                   @Override  
  5.                   public void onCompleted() {  
  6.                       log.d("done loading all data");  
  7.                   }  
  8.   
  9.                   @Override  
  10.                   public void onError(Throwable e) {  
  11.                       log.d("error");  
  12.                   }  
  13.   
  14.                   @Override  
  15.                   public void onNext(String data) {  
  16.                       log.d("all merged data will pass here one by one!")  
  17.               });  

七、使用concat和first做快取

  依次檢查memory、disk和network中是否存在資料,任何一步一旦發現資料後面的操作都不執行。

[html] view plain copy
  1. Observable<String> memory = Observable.create(new Observable.OnSubscribe<String>() {  
  2.     @Override  
  3.     public void call(Subscriber<? super String> subscriber) {  
  4.         if (memoryCache != null) {  
  5.             subscriber.onNext(memoryCache);  
  6.         } else {  
  7.             subscriber.onCompleted();  
  8.         }  
  9.     }  
  10. });  
  11. Observable<String> disk = Observable.create(new Observable.OnSubscribe<String>() {  
  12.     @Override  
  13.     public void call(Subscriber<? super String> subscriber) {  
  14.         String cachePref = rxPreferences.getString("cache").get();  
  15.         if (!TextUtils.isEmpty(cachePref)) {  
  16.             subscriber.onNext(cachePref);  
  17.         } else {  
  18.             subscriber.onCompleted();  
  19.         }  
  20.     }  
  21. });  
  22.   
  23. Observable<String> network = Observable.just("network");  
  24.   
  25. //依次檢查memory、disk、network  
  26. Observable.concat(memory, disk, network)  
  27. .first()  
  28. .subscribeOn(Schedulers.newThread())  
  29. .subscribe(s -> {  
  30.     memoryCache = "memory";  
  31.     System.out.println("--------------subscribe: " + s);  
  32. });  

八、使用timer做定時操作。當有“x秒後執行y操作”類似的需求的時候,想到使用timer

例如:2秒後輸出日誌“hello world”,然後結束。

[html] view plain copy
  1. Observable.timer(2, TimeUnit.SECONDS)  
  2.               .subscribe(new Observer<Long>() {  
  3.                   @Override  
  4.                   public void onCompleted() {  
  5.                       log.d ("completed");  
  6.                   }  
  7.   
  8.                   @Override  
  9.                   public void onError(Throwable e) {  
  10.                       log.e("error");  
  11.                   }  
  12.   
  13.                   @Override  
  14.                   public void onNext(Long number) {  
  15.                       log.d ("hello world");  
  16.                   }  
  17.               });  

九、使用interval做週期性操作。當有“每隔xx秒後執行yy操作”類似的需求的時候,想到使用interval

例如:每隔2秒輸出日誌“helloworld”。

[html] view plain copy
  1. Observable.interval(2, TimeUnit.SECONDS)  
  2.          .subscribe(new Observer<Long>() {  
  3.              @Override  
  4.              public void onCompleted() {  
  5.                 log.d ("completed");  
  6.              }  
  7.   
  8.              @Override  
  9.              public void onError(Throwable e) {  
  10.                 log.e("error");  
  11.              }  
  12.   
  13.              @Override  
  14.              public void onNext(Long number) {  
  15.                 log.d ("hello world");  
  16.              }  
  17.          });  


十、使用throttleFirst防止按鈕重複點選

ps:debounce也能達到同樣的效果

[html] view plain copy
  1. RxView.clicks(button)  
  2.               .throttleFirst(1, TimeUnit.SECONDS)  
  3.               .subscribe(new Observer<Object>() {  
  4.                   @Override  
  5.                   public void onCompleted() {  
  6.                         log.d ("completed");  
  7.                   }  
  8.   
  9.                   @Override  
  10.                   public void onError(Throwable e) {  
  11.                         log.e("error");  
  12.                   }  
  13.   
  14.                   @Override  
  15.                   public void onNext(Object o) {  
  16.                        log.d("button clicked");  
  17.                   }  
  18.               });  


十一、使用schedulePeriodically做輪詢請求


[html] view plain copy
  1. Observable.create(new Observable.OnSubscribe<String>() {  
  2.             @Override  
  3.             public void call(final Subscriber<? super String> observer) {  
  4.   
  5.                 Schedulers.newThread().createWorker()  
  6.                       .schedulePeriodically(new Action0() {  
  7.                           @Override  
  8.                           public void call() {  
  9.                               observer.onNext(doNetworkCallAndGetStringResult());  
  10.                           }  
  11.                       }, INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS);  
  12.             }  
  13.         }).subscribe(new Action1<String>() {  
  14.             @Override  
  15.             public void call(String s) {  
  16.                 log.d("polling….”));  
  17.             }  
  18.         })  


十二、RxJava進行陣列、list的遍歷

[html] view plain copy
  1. String[] names = {"Tom", "Lily", "Alisa", "Sheldon", "Bill"};  
  2. Observable  
  3.         .from(names)  
  4.         .subscribe(new Action1<String>() {  
  5.             @Override  
  6.             public void call(String name) {  
  7.                 log.d(name);  
  8.             }  
  9.         });  

十三、解決巢狀回撥(callback hell)問題

[html] view plain copy
  1. NetworkService.getToken("username", "password")  
  2.     .flatMap(s -> NetworkService.getMessage(s))  
  3.     .subscribe(s -> {  
  4.         System.out.println("message: " + s);  
  5. })  

十四、響應式的介面

比如勾選了某個checkbox,自動更新對應的preference

[html] view plain copy
  1. SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);  
  2. RxSharedPreferences rxPreferences = RxSharedPreferences.create(preferences);  
  3.   
  4. Preference<Boolean> checked = rxPreferences.getBoolean("checked", true);  
  5.   
  6. CheckBox checkBox = (CheckBox) findViewById(R.id.cb_test);  
  7. RxCompoundButton.checkedChanges(checkBox)  
  8.         .subscribe(checked.asAction());  


最後,由於個人能力有限,文章難免有疏漏之處,如果您有任何疑議,請讓我知道,謝謝!本文所有的例子已經上傳到github上


致謝:這篇文章的絕大多數例子是從這裡總結的,還有部分例子來自這裡。對作者的無私貢獻表示感謝!

相關文章