使用RxBus有一段時(shí)間了,記得剛使用的使用我在ActivityB中去注冊(cè)RxBus,這個(gè)時(shí)候ActivityB還沒(méi)有啟動(dòng),然后我在ActivityA中post事件后啟動(dòng)ActivityB,然而ActivityB并沒(méi)有接收到任何事件,當(dāng)時(shí)還郁悶了很久拖刃。
ActivityB接收不到事件的主要原因在于我們的ActivityB create之前發(fā)送了事件這個(gè)時(shí)候由于我們ActivityB并沒(méi)有創(chuàng)建,所以也沒(méi)有進(jìn)行事件注冊(cè)蕉堰,當(dāng)然收不到任何事件了,我當(dāng)時(shí)的做法是調(diào)用handler.postDelay(500)進(jìn)行延遲一下發(fā)送事件,這個(gè)時(shí)間是我測(cè)試ActivityB完全創(chuàng)建后的時(shí)間,這個(gè)時(shí)候由于ActivityB已經(jīng)創(chuàng)建并且注冊(cè)了事件访得,ActivityA發(fā)送的事件也可以被接收了,但是這種做法并不優(yōu)雅靠譜围小,因?yàn)锳ctivity創(chuàng)建時(shí)間多少完全不可預(yù)料,導(dǎo)致我們沒(méi)辦法去估計(jì)一個(gè)準(zhǔn)確的延遲事件,并且這種做法實(shí)在不優(yōu)雅锨阿。们豌。涯捻。浅妆。
所以我一直在想難道事件只能在Activity創(chuàng)建后才能發(fā)送嗎?可以不可在它創(chuàng)建前就發(fā)送,創(chuàng)建成功后接受到呢障癌?
我們看下面實(shí)現(xiàn)代碼
/**
* Created by wubo on 2017/6/2.
*/
public class RxBus<T> {
private static RxBus mRxBus;
private PublishProcessor<T> mPublishProcessor;
private ConcurrentHashMap<Class, T> mConcurrentHashMap;
private RxBus() {
mPublishProcessor = PublishProcessor.create();
mConcurrentHashMap = new ConcurrentHashMap();
}
public static RxBus getInstance() {
if (mRxBus == null) {
synchronized (RxBus.class) {
if (mRxBus == null) {
mRxBus = new RxBus();
}
}
}
return mRxBus;
}
//register
public Flowable<T> registerEvent(Class<T> clazz) {
Flowable <T>tFlowable = mPublishProcessor.ofType(clazz);
return tFlowable;
}
public void post(T event) {
mPublishProcessor.onNext(event);
}
public Flowable registerStickEvent(final Class<T> clazz) {
final T t = mConcurrentHashMap.get(clazz);
if (t != null) {
Flowable<T> tFlowable = mPublishProcessor.ofType(clazz);
return tFlowable.mergeWith(Flowable.create(new FlowableOnSubscribe<T>() {
@Override
public void subscribe(FlowableEmitter<T> e) throws Exception {
e.onNext(t);
}
}, BackpressureStrategy.BUFFER));
}
return mPublishProcessor;
}
public void postStick(T event) {
T t = mConcurrentHashMap.get(event.getClass());
if (t == null) {
mConcurrentHashMap.put(event.getClass(), event);
}
post(event);
}
public void removeAllStickEvent(){
mConcurrentHashMap.clear();
}
}
我們可以這么寫(xiě)凌外,為什么Stick事件注冊(cè)的時(shí)候需要合并一個(gè)流呢,因?yàn)槿绻覀冞@里首先需要返回一個(gè)Flowable提供訂閱的涛浙,那么如果我們直接返回mPublishProcessor的話我們?cè)趺唇邮盏絊tick事件呢康辑? 所以我們merge一個(gè)流當(dāng)我們注冊(cè)時(shí)就發(fā)送我們map中存入的stick事件。
這里還有個(gè)小問(wèn)題轿亮,當(dāng)我們訂閱一個(gè)被觀察者我們銷毀的時(shí)候需要解除訂閱疮薇,否則會(huì)繼續(xù)持有引用對(duì)象,導(dǎo)致內(nèi)存泄露.
Flowable<String> flowable = RxBus.getInstance().registerStickEvent(String.class);
flowable.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.e("wwwSecondActivity",s);
}
});
比如這段代碼哀托,我們?cè)赟econdActivity中使用RxBus注冊(cè)一個(gè)Stick事件惦辛,然后在MainActivity中開(kāi)開(kāi)心心的調(diào)用
RxBus.getInstance().postStick("MainActivity");
發(fā)送一個(gè)Stick事件
好我們看看Log打印日志
點(diǎn)擊按鈕跳到第二個(gè)界面
06-03 16:15:06.051 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
吆西貌似效果不錯(cuò)哦~~等等我們按返回鍵退出這個(gè)界面然后再進(jìn)來(lái)試一試
06-03 16:16:46.714 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
06-03 16:16:46.749 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
這。仓手。這怎么回事胖齐,我只發(fā)送一次,怎么收到二個(gè)事件抱著大大的?我返回這個(gè)界面再進(jìn)來(lái)一次看看嗽冒,
06-03 16:18:00.767 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
06-03 16:18:00.767 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
06-03 16:18:00.814 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
可以看到情況很不妙每次我們退出界面再進(jìn)來(lái)的時(shí)候這個(gè)事件就會(huì)多接收一次一直累加呀伙,我們分析一下問(wèn)題可能出現(xiàn)在哪。
在上一篇關(guān)于RxBus實(shí)現(xiàn)思考我們分析到當(dāng)我們使用subject onNext()去發(fā)送事件時(shí)候我們會(huì)發(fā)送到我們所有用subject 訂閱
的里面添坊,而我們第一次接收一次說(shuō)明我們訂閱了一次剿另,而退出來(lái)再進(jìn)來(lái)接收到二次說(shuō)明我們訂閱了二次,可你會(huì)疑惑我界面都退出了啊贬蛙,不錯(cuò)雨女,Rx是不會(huì)主動(dòng)幫你去解除你的訂閱關(guān)系的,所以當(dāng)你第一次訂閱的時(shí)候雖然你退出了但是被訂閱者引用還在RxBus的Subject里阳准,每訂閱并退出一次氛堕,這個(gè)引用會(huì)增加一個(gè),所以當(dāng)你發(fā)送事件的時(shí)候滿足類型會(huì)接收之前所有訂閱過(guò)的事件野蝇。
哪這多坑啊怎么辦呢讼稚?沒(méi)事rx可能也想到一點(diǎn)幫我提供一個(gè)CompositeDisposable類,它可以組裝我們所有的訂閱關(guān)系绕沈,然后統(tǒng)一進(jìn)行解綁锐想,我們可以創(chuàng)建一個(gè)方法
public void addDispose(Disposable disposable){
mCompositeDisposable.add(disposable);
}
然后在onDesdory()中進(jìn)行統(tǒng)一解綁
@Override
protected void onDestroy() {
super.onDestroy();
if(mCompositeDisposable!=null&&!mCompositeDisposable.isDisposed()){
mCompositeDisposable.dispose();
}
RxBus.getInstance().removeAllStickEvent();
}
這樣不管我們?cè)趺赐顺鼋缑娑紱](méi)有關(guān)系,我們當(dāng)前注冊(cè)事件的界面只會(huì)一對(duì)一的接收發(fā)送過(guò)來(lái)的事件乍狐。
isDisposed()是2.0新方法判斷CompositeDisposable有沒(méi)有解綁
如果已經(jīng)解綁就會(huì)返回true如果沒(méi)有的話就返回false
我們看看源碼是不是這樣
@Override
public void dispose() {
if (disposed) {
return;
}
OpenHashSet<Disposable> set;
synchronized (this) {
if (disposed) {
return;
}
disposed = true;
set = resources;
resources = null;
}
dispose(set);
}
@Override
public boolean isDisposed() {
return disposed;
}
isDisposed()返回disposed變量而當(dāng)我們調(diào)用dispose()丟棄我們綁定關(guān)系后 disposed = true;會(huì)被賦值為true
@Override
public boolean add(Disposable d) {
ObjectHelper.requireNonNull(d, "d is null");
if (!disposed) {
synchronized (this) {
if (!disposed) {
OpenHashSet<Disposable> set = resources;
if (set == null) {
set = new OpenHashSet<Disposable>();
resources = set;
}
set.add(d);
return true;
}
}
}
d.dispose();
return false;
}
add方法也是如此如果disposed是true的話說(shuō)明已經(jīng)解綁就不添加到集合里,直接把參數(shù)解綁然后返回false說(shuō)明添加失敗.