前言
在Android EventBus3.x的使用詳解一文中我們?nèi)嬷v解了使用EvenBus3.x解決進(jìn)程/界面通信袱衷。
本文將介紹另一個東西—>使用RxBus來實(shí)現(xiàn)進(jìn)程/界面通信。
閱讀本文胯舷,你需要提前了解RxJava,可以查看:
給 Android 開發(fā)者的 RxJava 詳解
Android響應(yīng)式編程框架—RxJava&RxAndroid2.0使用筆記
RxBus簡介
什么是RxBus妓盲?
RxBus 名字看起來像一個庫允耿,但它并不是一個庫,而是一種模式储笑,它的思想是使用RxJava來實(shí)現(xiàn)了EventBus 茧泪,而讓你不再需要使用 Otto 或者 GreenRobot 的 EventBus蜓氨。------ 給 Android 開發(fā)者的 RxJava 詳解
RxBus2.x就是基于RxJava2.x封裝實(shí)現(xiàn)的類。
為什么要使用RxBus队伟?
如上所說穴吹,我們可以通過封裝RxJava實(shí)現(xiàn)EventBus。
隨著RxJava在Android項(xiàng)目中的普及, 我們完全可以使用RxBus代替EventBus嗜侮,減少庫的引入港令,增加系統(tǒng)的穩(wěn)定性。
EventBus雖然使用方便锈颗,但是在事件的生命周期的處理上需要我們利用訂閱者的生命周期去注冊和取消注冊顷霹,這個部分還是略有麻煩之處。
而我們可以結(jié)合使用RxLifecycle來配置击吱,簡化這一步驟淋淀。
結(jié)合RxJava的強(qiáng)大能力和RxAndroid的進(jìn)程調(diào)度,RxBus有更多更強(qiáng)大的功能姨拥。
Demo&代碼
GitHub:https://github.com/DeMonLiu623/DeMon-RxBus
RxBus實(shí)現(xiàn)
Gradle
implementation 'io.reactivex.rxjava2:rxjava:2.1.17' //RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' //RxAndroid
封裝RxJava實(shí)現(xiàn)RxBus
Subject有兩種用途:
做為observable向其他的observable發(fā)送事件
做為observer接收其他的observable發(fā)送的事件
我們要實(shí)現(xiàn):事件總線绅喉、事件發(fā)布者以及事件訂閱者渠鸽。首先Subject既可以作為被觀察者發(fā)送事件叫乌,也可以作為觀察者接收事件柴罐,而RxJava內(nèi)部的響應(yīng)式的支持實(shí)現(xiàn)了事件總線的功能。
可以使用PublishSubject.create().toSerialized();生成一個Subject對象憨奸。
如下代碼就實(shí)現(xiàn)了最基本的RxBus革屠。
public class RxBus {
private volatile static RxBus mDefaultInstance;
private final Subject<Object> mBus;
private RxBus() {
mBus = PublishSubject.create().toSerialized();
}
public static RxBus getInstance() {
if (mDefaultInstance == null) {
synchronized (RxBus.class) {
if (mDefaultInstance == null) {
mDefaultInstance = new RxBus();
}
}
}
return mDefaultInstance;
}
/**
* 發(fā)送事件
*/
public void post(Object event) {
mBus.onNext(event);
}
/**
* 根據(jù)傳遞的 eventType 類型返回特定類型(eventType)的 被觀察者
*/
public <T> Observable<T> toObservable(final Class<T> eventType) {
return mBus.ofType(eventType);
}
/**
* 判斷是否有訂閱者
*/
public boolean hasObservers() {
return mBus.hasObservers();
}
public void reset() {
mDefaultInstance = null;
}
}
使用RxBus
事件實(shí)體
public class MsgEvent {
private String msg;
public MsgEvent(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
訂閱事件
RxBus.getInstance().toObservable(MsgEvent.class).subscribe(new Observer<MsgEvent>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(MsgEvent msgEvent) {
//處理事件
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
發(fā)送事件
RxBus.getInstance().post(new MsgEvent("Java"));
與EventBus對比,除了訂閱事件的消息處理排宰,使用基本一樣似芝。
至于EventBus的線程模型,我們完全可以使用RxJava 的線程控制Scheduler來實(shí)現(xiàn)板甘,具體可以參考上面RxJava的使用兩篇文章党瓮。
RxBus內(nèi)存泄漏
使用RxJava發(fā)布一個訂閱后,當(dāng)頁面被finish盐类,此時訂閱邏輯還未完成寞奸,如果沒有及時取消訂閱,就會導(dǎo)致Activity/Fragment無法被回收在跳,從而引發(fā)內(nèi)存泄漏枪萄。
EventBus為了解決這個問題,要求我們根據(jù)訂閱者的生命周期注冊和取消注冊猫妙。所以在RxBus中我們也可以這樣操作瓷翻。
簡單處理
使用一個CompositeDisposable存儲當(dāng)前所有的訂閱,然后再onDestroy()中將其dispose()割坠。
private CompositeDisposable compositeDisposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
compositeDisposable = new CompositeDisposable();
RxBus.getInstance().toObservable(MsgEvent.class).subscribe(new Observer<MsgEvent>() {
@Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
@Override
public void onNext(MsgEvent msgEvent) {
//事件處理
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
unbinder.unbind();
if (compositeDisposable!=null && !compositeDisposable.isDisposed()){
compositeDisposable.dispose();
}
}
RxLifecycle
Rxlifecycle 是trello開發(fā)的用于解決RxJava引起的內(nèi)存泄漏的開源框架齐帚。
GitHub地址:https://github.com/trello/RxLifecycle
該框架為了適應(yīng)不同的場景,開發(fā)了不同的版本,具體的可以查看GitHub文檔:
// RxLifecycle基礎(chǔ)庫
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2'
// Android使用的庫彼哼,可以綁定特定的生命周期
//需繼承RxActvivty使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2'
// Android組件庫对妄,里面定義了例如RxAppCompatActivity、RxFragment之類的Android組件
// 須繼承RxAppCompatActivity沪羔、RxFragment使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'
// 預(yù)先編寫的支持首選項(xiàng)片段饥伊,將其子類化為提供者
implementation 'com.trello.rxlifecycle2:rxlifecycle-components-preference:2.2.2'
// Android使用的庫,須繼承NaviActivity使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-navi:2.2.2'
// 使用Android生命周期作為提供者
//無需繼承蔫饰,任何有聲明周期的組件都可以直接使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2'
// Kotlin語法
implementation 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.2.2'
//在Kotlin語法琅豆,使用Android生命周期
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.2.2'
如果我們自己有BaseActivity,所以不能繼承RxActvivty篓吁,RxAppCompatActivity茫因、RxFragment,NaviActivity杖剪。
為了保持代碼的靈活性冻押,我們使用:
// 使用Android生命周期作為提供者
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2'
修改RxBus驰贷,添加如下代碼:
使用compose(this.bindToLifecycle())方法綁定Activity的生命周期,在onStart方法中綁定洛巢,在onStop方法被調(diào)用后就會解除綁定括袒,以此類推。
如果在onPause/onStop方法中綁定稿茉,那么就會在它的下一個生命周期方法(onStop/onDestory)被調(diào)用后解除綁定锹锰。
綁定 | 銷毀 |
---|---|
onCreate | onDestory |
onStart | onStop |
onResum | onPause |
onPause | onStop |
onStop | onDestory |
/**
* 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
*/
public <T> Observable<T> toObservable(LifecycleOwner owner, final Class<T> eventType) {
LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
return mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
}
訂閱事件時,添加上下文this即可綁定生命周期漓库,自動取消訂閱:
RxBus.getInstance().toObservable(this,MsgEvent.class).subscribe(new Consumer<MsgEvent>() {
@Override
public void accept(MsgEvent msgEvent) throws Exception {
//處理事件
}
});
RxBus的粘性事件
EventBus有粘性事件恃慧,RxBus也可以實(shí)現(xiàn)。
修改RxBus修改&添加如下代碼:
private final Map<Class<?>, Object> mStickyEventMap;
private RxBus() {
mBus = PublishSubject.create().toSerialized();
mStickyEventMap = new ConcurrentHashMap<>();
}
/**
* 發(fā)送一個新Sticky事件
*/
public void postSticky(Object event) {
synchronized (mStickyEventMap) {
mStickyEventMap.put(event.getClass(), event);
}
post(event);
}
/**
* 根據(jù)傳遞的 eventType 類型返回特定類型(eventType)的 被觀察者
* 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
*/
public <T> Observable<T> toObservableSticky(LifecycleOwner owner,final Class<T> eventType) {
synchronized (mStickyEventMap) {
LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
Observable<T> observable = mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
final Object event = mStickyEventMap.get(eventType);
if (event != null) {
return observable.mergeWith(Observable.create(new ObservableOnSubscribe<T>() {
@Override
public void subscribe(ObservableEmitter<T> subscriber) throws Exception {
subscriber.onNext(eventType.cast(event));
}
}));
} else {
return observable;
}
}
}
/**
* 根據(jù)eventType獲取Sticky事件
*/
public <T> T getStickyEvent(Class<T> eventType) {
synchronized (mStickyEventMap) {
return eventType.cast(mStickyEventMap.get(eventType));
}
}
/**
* 移除指定eventType的Sticky事件
*/
public <T> T removeStickyEvent(Class<T> eventType) {
synchronized (mStickyEventMap) {
return eventType.cast(mStickyEventMap.remove(eventType));
}
}
/**
* 移除所有的Sticky事件
*/
public void removeAllStickyEvents() {
synchronized (mStickyEventMap) {
mStickyEventMap.clear();
}
}
RxBus完整代碼
public class RxBus {
private volatile static RxBus mDefaultInstance;
private final Subject<Object> mBus;
private final Map<Class<?>, Object> mStickyEventMap;
private RxBus() {
mBus = PublishSubject.create().toSerialized();
mStickyEventMap = new ConcurrentHashMap<>();
}
public static RxBus getInstance() {
if (mDefaultInstance == null) {
synchronized (RxBus.class) {
if (mDefaultInstance == null) {
mDefaultInstance = new RxBus();
}
}
}
return mDefaultInstance;
}
/**
* 發(fā)送事件
*/
public void post(Object event) {
mBus.onNext(event);
}
/**
* 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
*/
public <T> Observable<T> toObservable(LifecycleOwner owner, final Class<T> eventType) {
LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
return mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
}
/**
* 判斷是否有訂閱者
*/
public boolean hasObservers() {
return mBus.hasObservers();
}
public void reset() {
mDefaultInstance = null;
}
/**
* Stciky 相關(guān)
*/
/**
* 發(fā)送一個新Sticky事件
*/
public void postSticky(Object event) {
synchronized (mStickyEventMap) {
mStickyEventMap.put(event.getClass(), event);
}
post(event);
}
/**
* 根據(jù)傳遞的 eventType 類型返回特定類型(eventType)的 被觀察者
* 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
*/
public <T> Observable<T> toObservableSticky(LifecycleOwner owner,final Class<T> eventType) {
synchronized (mStickyEventMap) {
LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
Observable<T> observable = mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
final Object event = mStickyEventMap.get(eventType);
if (event != null) {
return observable.mergeWith(Observable.create(new ObservableOnSubscribe<T>() {
@Override
public void subscribe(ObservableEmitter<T> subscriber) throws Exception {
subscriber.onNext(eventType.cast(event));
}
}));
} else {
return observable;
}
}
}
/**
* 根據(jù)eventType獲取Sticky事件
*/
public <T> T getStickyEvent(Class<T> eventType) {
synchronized (mStickyEventMap) {
return eventType.cast(mStickyEventMap.get(eventType));
}
}
/**
* 移除指定eventType的Sticky事件
*/
public <T> T removeStickyEvent(Class<T> eventType) {
synchronized (mStickyEventMap) {
return eventType.cast(mStickyEventMap.remove(eventType));
}
}
/**
* 移除所有的Sticky事件
*/
public void removeAllStickyEvents() {
synchronized (mStickyEventMap) {
mStickyEventMap.clear();
}
}
}
Demo
該Demo演示了使用RxBus完成Activty與Fragment的通信渺蒿。
public class RxActivity extends AppCompatActivity {
@BindView(R.id.java)
Button java;
@BindView(R.id.android)
Button android;
@BindView(R.id.rx_layout)
FrameLayout rxLayout;
private FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rx);
ButterKnife.bind(this);
fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.rx_layout, new RxFragment());
transaction.commit();
}
@OnClick({R.id.java, R.id.android})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.java:
RxBus.getInstance().post(new MsgEvent("Java"));
break;
case R.id.android:
RxBus.getInstance().post(new MsgEvent("Android"));
break;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/java"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Java" />
<Button
android:id="@+id/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android" />
</LinearLayout>
<FrameLayout
android:id="@+id/rx_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
public class RxFragment extends Fragment {
@BindView(R.id.text)
TextView text;
Unbinder unbinder;
private View view;
@SuppressLint("CheckResult")
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_rx, container, false);
unbinder = ButterKnife.bind(this, view);
RxBus.getInstance().toObservable(this,MsgEvent.class).subscribe(new Consumer<MsgEvent>() {
@Override
public void accept(MsgEvent msgEvent) throws Exception {
//處理事件
}
});
return view;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="RxFragment"
android:textSize="18sp" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textSize="16sp" />
</LinearLayout>
轉(zhuǎn)自:https://blog.csdn.net/demonliuhui/article/details/82532078