背景
是否有這樣的糾結:
在已經習慣了EventBus的用法後,轉戰RxBus使用方法的不一致,導致多餘的學習和使用成本
已經使用rxjava和rxAndroid到你的專案中,但是專案中又同時存在eventbus;因為rx完全可以替換掉eventbus所以導致了過多引入第三方jar包的問題,對於有程式碼潔癖和瘦身需求的同學們來說簡直是一個噩耗;
如何在最大基礎上修改我們已經存在的程式碼呢,那就是改造一個自己的rxbus,讓他使用起來和eventbus一模一樣,這樣我們只需要將eventbus改名成rxbus即可,其他程式碼都不需要修改!
廢話到此為止,開始我們的優化之路
效果
工程目錄
程式碼使用
註冊-登出-接受事件
/*接受事件*/ @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的同學一眼就應該能看出,用法完全一模一樣
封裝原理
封裝註解
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
int code() default -1;
ThreadMode threadMode() default ThreadMode.CURRENT_THREAD;
}複製程式碼
暫時我們們先了解ThreadMode 引數,code引數的使用在結尾再給大家解釋(比eventbus新增的一個功能)
ThreadMode 指定接受訊息的處理所在的執行緒,我們這裡定義了四種情況
處理模式
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封裝
集合上面的類,開始我們的rxbus封裝
初始化單利物件
感興趣的同學可以檢視另一篇關於單利部落格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);
}
}複製程式碼
post請求
觸發請求
/**
* 提供了一個新的事件,單一型別
*
* @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);
}複製程式碼
code-post請求,更加方便
在借鑑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,可自行替換你使用的版本