1、功能防抖
- 用户在规定时间内触发多次该功能,仅会响应第一次该功能
- RxView.clicks源码分析
eg:短时间内连续点击按钮
public static void throttleFirst() { Button button = null; RxView.clicks(button) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer<Object>() { @Override public void accept(Object o) throws Exception { //跳转 } }); }
2、联想搜索优化
RxTextView.textChanges源码分析
采用skip(1)原因:跳过 第1次请求 = 初始输入框的空字符状态
public static void search() { EditText editText = null; RxTextView.textChanges(editText) .debounce(1, TimeUnit.SECONDS) .skip(1) .subscribe(new Consumer<CharSequence>() { @Override public void accept(CharSequence charSequence) throws Exception { //开始搜索 } }); }
3、联合判断
- activity.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="请填写姓名" /> <EditText android:id="@+id/age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="请填写年龄" /> <EditText android:id="@+id/job" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="请填写职业" /> <Button android:id="@+id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="提交" android:enabled="false" /> </LinearLayout>
Observable<CharSequence> nameObservable = RxTextView.textChanges(name).skip(1); Observable<CharSequence> ageObservable = RxTextView.textChanges(age).skip(1); Observable<CharSequence> jobObservable = RxTextView.textChanges(job).skip(1); /* * 通过combineLatest()合并事件 & 联合判断 **/ Observable.combineLatest(nameObservable,ageObservable,jobObservable,new Function3<CharSequence, CharSequence, CharSequence,Boolean>() { @Override public Boolean apply(@NonNull CharSequence name, @NonNull CharSequence age, @NonNull CharSequence job) throws Exception { //1. 姓名 boolean isUserNameValid = !TextUtils.isEmpty(name) // 2. 年龄信息 boolean isUserAgeValid = !TextUtils.isEmpty(age); // 3. 职业信息 boolean isUserJobValid = !TextUtils.isEmpty(job) ; return isUserNameValid && isUserAgeValid && isUserJobValid; } }).subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean s) throws Exception { Log.e(TAG, "提交按钮是否可点击: " + s); list.setEnabled(s); } });
4、数据源合并
/ 用于存放最终展示的数据 String result = "数据源来自 = " ; /* * 设置第1个Observable:通过网络获取数据 * 此处仅作网络请求的模拟 **/ Observable<String> network = Observable.just("网络"); /* * 设置第2个Observable:通过本地文件获取数据 * 此处仅作本地文件请求的模拟 **/ Observable<String> file = Observable.just("本地文件"); /* * 通过merge()合并事件 & 同时发送事件 **/ Observable.merge(network, file) .subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String value) { Log.d(TAG, "数据源有: "+ value ); result += value + "+"; } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } // 接收合并事件后,统一展示 @Override public void onComplete() { Log.d(TAG, "获取数据完成"); Log.d(TAG, result ); } });
5、网络/缓存策略
// 该2变量用于模拟内存缓存 & 磁盘缓存中的数据 String memoryCache = null; String diskCache = "从磁盘缓存中获取数据"; /* * 设置第1个Observable:检查内存缓存是否有该数据的缓存 **/ Observable<String> memory = Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> emitter) throws Exception { // 先判断内存缓存有无数据 if (memoryCache != null) { // 若有该数据,则发送 emitter.onNext(memoryCache); } else { // 若无该数据,则直接发送结束事件 emitter.onComplete(); } } }); /* * 设置第2个Observable:检查磁盘缓存是否有该数据的缓存 **/ Observable<String> disk = Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> emitter) throws Exception { // 先判断磁盘缓存有无数据 if (diskCache != null) { // 若有该数据,则发送 emitter.onNext(diskCache); } else { // 若无该数据,则直接发送结束事件 emitter.onComplete(); } } }); /* * 设置第3个Observable:通过网络获取数据 **/ Observable<String> network = Observable.just("从网络中获取数据"); // 此处仅作网络请求的模拟 /* * 通过concat() 和 firstElement()操作符实现缓存功能 **/ // 1. 通过concat()合并memory、disk、network 3个被观察者的事件(即检查内存缓存、磁盘缓存 & 发送网络请求) // 并将它们按顺序串联成队列 Observable.concat(memory, disk, network) // 2. 通过firstElement(),从串联队列中取出并发送第1个有效事件(Next事件),即依次判断检查memory、disk、network .firstElement() // 即本例的逻辑为: // a. firstElement()取出第1个事件 = memory,即先判断内存缓存中有无数据缓存;由于memoryCache = null,即内存缓存中无数据,所以发送结束事件(视为无效事件) // b. firstElement()继续取出第2个事件 = disk,即判断磁盘缓存中有无数据缓存:由于diskCache ≠ null,即磁盘缓存中有数据,所以发送Next事件(有效事件) // c. 即firstElement()已发出第1个有效事件(disk事件),所以停止判断。 // 3. 观察者订阅 .subscribe(new Consumer<String>() { @Override public void accept( String s) throws Exception { Log.d(TAG,"最终获取的数据来源 = "+ s); } });
6、轮询器
Disposable mDisposable; //开启轮询 public void autoLoop() { if (mDisposable == null || mDisposable.isDisposed()) { Observable.interval(0, 5, TimeUnit.SECONDS) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<Long>() { @Override public void accept(Long aLong) throws Exception { } }); } } //关闭轮询 public void stopLoop() { if (mDisposable != null && !mDisposable.isDisposed()) { mDisposable.dispose(); mDisposable = null; } }
7、定时器
//一段时间之后再做一些事情
public void timer() { Observable.timer(5, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<Long>() { @Override public void accept(Long aLong) throws Exception { } }); }
8、倒计时
public static void countDown(final int count) { Observable.intervalRange(0, count, 0, 1, TimeUnit.SECONDS) .map(new Function<Long, Long>() { @Override public Long apply(Long aLong) throws Exception { return count - aLong; } }) .subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { Log.d(TAG, "onSubscribe"); } @Override public void onNext(Long value) { Log.d(TAG, "onNext: value = " + value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { Log.d(TAG, "onComplete"); } }); }