是否有這樣的糾結:java
在已經習慣了EventBus的用法後,轉戰RxBus使用方法的不一致,致使多餘的學習和使用成本react
已經使用rxjava和rxAndroid到你的項目中,可是項目中又同時存在eventbus;由於rx徹底能夠替換掉eventbus因此致使了過多引入第三方jar包的問題,對於有代碼潔癖和瘦身需求的同窗們來講簡直是一個噩耗;
如何在最大基礎上修改咱們已經存在的代碼呢,那就是改造一個本身的rxbus,讓他使用起來和eventbus如出一轍,這樣咱們只須要將eventbus更名成rxbus便可,其餘代碼都不須要修改!android
廢話到此爲止,開始咱們的優化之路git
註冊-註銷-接受事件github
/*接受事件*/
@Subscribe(threadMode= ThreadMode.MAIN)
public void event(EventChangeText changeText){
tvChange.setText(changeText.getChangeText());
}
@Override
protected void onStart() {
super.onStart();
/*註冊*/
RxBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
/*註銷*/
RxBus.getDefault().unRegister(this);
}複製代碼
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_change_text:
RxBus.getDefault().post(new EventChangeText("我修改了-Main"));
break;
}
}複製代碼
用過EventBus的同窗一眼就應該能看出,用法徹底如出一轍ide
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
int code() default -1;
ThreadMode threadMode() default ThreadMode.CURRENT_THREAD;
}複製代碼
暫時我們先了解ThreadMode 參數,code參數的使用在結尾再給你們解釋(比eventbus添加的一個功能)
ThreadMode 指定接受消息的處理所在的線程,咱們這裏定義了四種狀況post
public enum ThreadMode {
/** * current thread */
CURRENT_THREAD,
/** * android main thread */
MAIN,
/** * new thread */
NEW_THREAD,
/** * io */
IO
}複製代碼
徹底是rx中自帶的四種處理模式學習
封裝處理過程當中的相關信息,模式,接收消息對象,code,接受消息類型優化
public class SubscriberMethod {
public Method method;
public ThreadMode threadMode;
public Class<?> eventType;
public Object subscriber;
public int code;
public SubscriberMethod(Object subscriber, Method method, Class<?> eventType, int code,ThreadMode threadMode) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.subscriber = subscriber;
this.code = code;
}
/** * 調用方法 * @param o 參數 */
public void invoke(Object o){
try {
method.invoke(subscriber, o);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}複製代碼
集合上面的類,開始咱們的rxbus封裝this
感興趣的同窗能夠查看另外一篇關於單利博客Android-主Activity不同的單利模式
private static volatile RxBus defaultInstance;
public static RxBus getDefault() {
RxBus rxBus = defaultInstance;
if (defaultInstance == null) {
synchronized (RxBus.class) {
rxBus = defaultInstance;
if (defaultInstance == null) {
rxBus = new RxBus();
defaultInstance = rxBus;
}
}
}
return rxBus;
}複製代碼
記錄註冊信息和發佈消息信息以及自定義的方法集合
private Map<Class, List<Subscription>> subscriptionsByEventType = new HashMap<>();
private Map<Object, List<Class>> eventTypesBySubscriber = new HashMap<>();
private Map<Class, List<SubscriberMethod>> subscriberMethodByEventType = new HashMap<>();複製代碼
register的時候獲取@Subscribe註解的方法的相關信息保存到map,post事件觸發的時候調用@Subscribe註解的方法並傳入參數.
/** * 註冊 * * @param subscriber 訂閱者 */
public void register(Object subscriber) {
Class<?> subClass = subscriber.getClass();
Method[] methods = subClass.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Subscribe.class)) {
//得到參數類型
Class[] parameterType = method.getParameterTypes();
//參數不爲空 且參數個數爲1
if (parameterType != null && parameterType.length == 1) {
Class eventType = parameterType[0];
addEventTypeToMap(subscriber, eventType);
Subscribe sub = method.getAnnotation(Subscribe.class);
int code = sub.code();
ThreadMode threadMode = sub.threadMode();
SubscriberMethod subscriberMethod = new SubscriberMethod(subscriber, method, eventType, code, threadMode);
addSubscriberToMap(eventType, subscriberMethod);
addSubscriber(subscriberMethod);
}
}
}
}複製代碼
unRegister的移除保存的subscriber、subscriberMethod已經Subscription取消訂閱事件
必定要及時的銷燬,否則內存泄露
/** * 取消註冊 * * @param subscriber */
public void unRegister(Object subscriber) {
List<Class> subscribedTypes = eventTypesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unSubscribeByEventType(eventType);
unSubscribeMethodByEventType(subscriber, eventType);
}
eventTypesBySubscriber.remove(subscriber);
}
}複製代碼
觸發請求
/** * 提供了一個新的事件,單一類型 * * @param o 事件數據 */
public void post(Object o) {
bus.onNext(o);
}複製代碼
調用rx處理回調
/** * 用RxJava添加訂閱者 * * @param subscriberMethod */
public void addSubscriber(final SubscriberMethod subscriberMethod) {
Observable observable;
if (subscriberMethod.code == -1) {
observable = toObservable(subscriberMethod.eventType);
} else {
observable = toObservable(subscriberMethod.code, subscriberMethod.eventType);
}
Subscription subscription = postToObservable(observable, subscriberMethod)
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
callEvent(subscriberMethod.code, o);
}
});
addSubscriptionToMap(subscriberMethod.eventType, subscription);
}複製代碼
在借鑑eventbus消息處理的模式上,新加入code判斷方式,這樣能夠更加快速的添加sub對象,不用一個消息初始化一個類,並且能夠同時區分一個消息的不一樣處理方式
效果
發送消息
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_change_text:
RxBus.getDefault().post(new EventChangeText("我修改了-Main"));
break;
case R.id.btn_code_simple:
RxBus.getDefault().post(0x1,"簡單的code消息");
break;
case R.id.btn_code_diffrent:
RxBus.getDefault().post(0x1,new EventChangeText("code方式-我修改了-Main"));
break;
}
}複製代碼
接收消息
/*單一code接受處理*/
@Subscribe(code = 0x1,threadMode= ThreadMode.MAIN)
public void event(String changeText){
tvChange.setText(changeText);
}
/*code 不一樣事件接受處理*/
@Subscribe(code = 0x1,threadMode= ThreadMode.MAIN)
public void eventCode(EventChangeText changeText){
tvChange.setText(changeText.getChangeText());
}
/*常規接受事件*/
@Subscribe(threadMode= ThreadMode.MAIN)
public void event(EventChangeText changeText){
tvChange.setText(changeText.getChangeText());
}複製代碼
看完之後估計你們都明白了使用方法,code實現的過車和ThreadMode實現原理同樣,在分發事件處理的時候,經過code的判斷達到這樣的目的結果
/** * 回調到訂閱者的方法中 * * @param code code * @param object obj */
private void callEvent(int code, Object object) {
Class eventClass = object.getClass();
List<SubscriberMethod> methods = subscriberMethodByEventType.get(eventClass);
if (methods != null && methods.size() > 0) {
for (SubscriberMethod subscriberMethod : methods) {
Subscribe sub = subscriberMethod.method.getAnnotation(Subscribe.class);
int c = sub.code();
if (c == code) {
subscriberMethod.invoke(object);
}
}
}
}複製代碼
compile 'com.wzgiceman:RxBus:1.0.2'複製代碼
推薦手動導入到本身的工程中,避免多餘的第三方jar包導入,只要你的工程中有對rx的支出,將文件copy到工程下面便可:
rx資源地址
/*rx-android-java*/
compile 'io.reactivex:rxjava:+'
compile 'com.squareup.retrofit:adapter-rxjava:+'
compile 'com.trello:rxlifecycle:+'
compile 'com.trello:rxlifecycle-components:+'複製代碼
演示工程中使用的是rx2,可自行替換你使用的版本