前言
當我第一次聽說RxJava是在2015年的11月,掐指一算距今過去了1年多了,現在RxJava2都發布了。現在公司項目的的業務需要,有一塊邏輯涉及到子線程和主線程的來回切換。如果使用傳統的Thread+Handler的寫法,寫出來的代碼就跳來跳去,還有可能出現多次嵌套。很利于閱讀理解里面的邏輯和后期的維護開發。早就聽說RxJava的大名,通過響應式編程很好的處理異步問題。這次正好有這個機會,自己就動手實踐一下。
Screen Shot 2017-01-14 at 18.27.50.png
產品流程
只有前一個執行完成(不管是否成功),才能執行后面一個。
- 新手引導
- 檢查升級
- 彈窗視圖
一張圖你就懂了
ezgif.com-video-to-gif.gif
開發流程
- 檢查sp里的isFirst-
子線程
- 顯示帶動畫的引導界面-
主線程
- 監聽動畫結束-
主線程
- 監聽引導界面的點擊事件-
主線程
- 隱藏帶動畫的引導界-
主線程
- 監聽動畫結束-
主線程
- 將sp里的isFirst置為false-
子線程
- 發起檢查版本請求-
子線程
- 顯示版本更新的dialog-
主線程
- 監聽對話框消失-
主線程
- 發起獲取彈窗數據的請求-
子線程
- 顯示彈窗視圖-
主線程
//TODO rxpreference 發送兩次
Disposable disposable = Observable
//返回:是否為第一次安裝
.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
e.onNext(PreferenceManager
.getDefaultSharedPreferences(context)
.getBoolean("isFirst", true));
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//返回:是否為第一次安裝
.flatMap(new Function<Boolean, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(Boolean aBoolean) throws Exception {
if (aBoolean) {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(final ObservableEmitter<Boolean> e) throws Exception {
AlphaAnimation alphaAnimation = new AlphaAnimation(0.1f, 1.0f);
alphaAnimation.setDuration(2000);
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (!e.isDisposed()) {
e.onNext(true);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
fragment_home_guide.setVisibility(View.VISIBLE);
fragment_home_guide.startAnimation(alphaAnimation);
}
});
} else {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
e.onNext(false);
}
});
}
}
})
//返回:是否為第一次安裝
.flatMap(new Function<Boolean, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(Boolean aBoolean) throws Exception {
if (aBoolean) {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(final ObservableEmitter<Boolean> e) throws Exception {
fragment_home_guide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!e.isDisposed()) {
e.onNext(true);
}
}
});
e.setDisposable(new Disposable() {
@Override
public void dispose() {
fragment_home_guide.setOnClickListener(null);
}
@Override
public boolean isDisposed() {
return true;
}
});
// e.add(new MainThreadSubscription() {
// @Override
// protected void onUnsubscribe() {
// fragment_home_guide.setOnClickListener(null);
// }
// });
}
});
} else {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
e.onNext(false);
}
});
}
}
})
//返回:是否為第一次安裝
.flatMap(new Function<Boolean, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(Boolean aBoolean) throws Exception {
if (aBoolean) {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(final ObservableEmitter<Boolean> e) throws Exception {
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.1f);
alphaAnimation.setDuration(2000);
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (!e.isDisposed()) {
e.onNext(true);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
fragment_home_guide.setVisibility(View.GONE);
fragment_home_guide.startAnimation(alphaAnimation);
}
});
} else {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
e.onNext(false);
}
});
}
}
})
.observeOn(Schedulers.io())
//返回:是否為第一次安裝
.map(new Function<Boolean, Boolean>() {
@Override
public Boolean apply(Boolean aBoolean) throws Exception {
if (aBoolean) {
PreferenceManager
.getDefaultSharedPreferences(context)
.edit()
.putBoolean("isFirst", false)
.apply();
}
return aBoolean;
}
})
//返回:最新版本的信息
.flatMap(new Function<Boolean, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Boolean aBoolean) throws Exception {
Thread.sleep(300);
return new Observable<String>() {
@Override
protected void subscribeActual(Observer<? super String> observer) {
observer.onNext("update info");
}
};
}
})
.observeOn(AndroidSchedulers.mainThread())
//返回:是否版本更新
.flatMap(new Function<String, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(String string) throws Exception {
if (string == null) {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
e.onNext(false);
}
});
} else {
return Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(final ObservableEmitter<Boolean> e) throws Exception {
new AlertDialog.Builder(context)
.setTitle("發現新版本")
.setMessage("更新內容")
.setPositiveButton("升級", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
e.onNext(true);
}
})
.create().show();
}
});
}
}
})
.observeOn(Schedulers.io())
//返回:彈窗工具信息
.flatMap(new Function<Boolean, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Boolean aBoolean) throws Exception {
Thread.sleep(300);
return Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("ok");
}
});
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Toast.makeText(HomeCheckActivity.this, s, Toast.LENGTH_SHORT).show();
}
});
disposables.add(disposable);
小結
在熟悉了RxJava的基本概念之后,寫Rx代碼確實比較順手,有一種行云流水的感覺。值得注意的是,使用RxJava進行開發并不會減少原有代碼量,反而有一定的增加。遇到的主要問題就是,要理解并區分subscribeOn和observeOn的線程控制,以及map和flatMap的變換。
我的粗淺理解是:
observeOn
作用于該操作符之后操作符直到出現新的observeOn操作符。subscribeOn
作用于該操作符之前的 Observable 的創建操符作以及 doOnSubscribe 操作符。
map是Observable對象沒有改變,執行形式變了,比如有File變成Bitmap。而flatMap是Observable發生了改變,比如以前被觀察的對象是sp里的isFirst,現在變成了引導界面的動畫結束。