1. 程式人生 > >Android_RxJava代替EventBus實現事件分發

Android_RxJava代替EventBus實現事件分發

歡迎加入技術談論群:714476794

一、背景

眾所周知,RxJava目前很火爆,既然RxJava是響應式的典型觀察者模式體現,那麼問題來了,我可不可以用RxJava實現頁面事件的通知,進而實現代替EventBus。這當然是可以實現的,下面開擼:

(一)、RxBus的建立

最開始的寫法:

RxBus

/**
 * Author KINCAI
 * .
 * description TODO
 * .
 * Time 2016-12-07 12:54
 */
public class RxBus {
    private final Subject<Object, Object>
            rxBus = new SerializedSubject<>(PublishSubject.create());
    private Map<String,Subscription> mSubscriptions = new HashMap<>();

    private RxBus() {
    }
    public static RxBus getInstance() {
        return RxBusInstance.instance;
    }


    private static class RxBusInstance{
        private static final RxBus instance = new RxBus();
    }

    public void send(EventBase eventBase){
        rxBus.onNext(eventBase);
    }
    public void register(final Object obj, final EventListener listener){
        if(obj == null)
            return;
       rxBus.observeOn(AndroidSchedulers.mainThread())
                .map(new Func1<Object, EventBase>() {
                    @Override
                    public EventBase call(Object s) {
                        return (EventBase) s;
                    }

                }).subscribe(new Action1<EventBase>() {
                    @Override
                    public void call(EventBase eventBase) {
                        listener.onEvent(eventBase);
                    }
                });

    }
    

    public interface EventListener {
        void onEvent(EventBase eventBase);
    }
}

EventBase實體類

/**
 * Author KINCAI
 * .
 * description TODO
 * .
 * Time 2016-12-07 16:11
 */
public class EventBase {
    private String tag;
    private String flag;
    private Object data;

    public EventBase(String tag, Object data) {
        this.tag = tag;
        this.data = data;
    }

    public EventBase(String tag, String flag, Object data) {
        this.tag = tag;
        this.flag = flag;
        this.data = data;
    }

    public EventBase() {
    }

    public String getTag() {
        return tag;
    }

    public void setTag(String tag) {
        this.tag = tag;
    }

    public String getFlag() {
        return flag;
    }

    public void setFlag(String flag) {
        this.flag = flag;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "EventBase{" +
                "tag='" + tag + '\'' +
                ", flag='" + flag + '\'' +
                ", data=" + data +
                '}';
    }
}

傳送訊息
 RxBus.getInstance().send(new EventBase(“new”,“new1”,"news"));

訂閱者
 RxBuss.getInstance().register(this, new RxBuss.EventListener() {
            @Override
            public void onEvent(EventBase eventBase) {
                LogUtils.e(eventBase.getTag());
            }
        });


新建RxBus類,宣告Subjcet<Object,Object> = new SerializedSubject<>(PublishSubject.create());

說明一下Subject可以看做是一個橋樑或者代理,充當了Observer和Observable的角色,也就是觀察者與被觀察者。

SerializedSubject可以處理併發,併發時只允許一個執行緒呼叫onnext等方法!。

PublishSubject是Subject的一種,它僅會向Observer釋放在訂閱之後Observable釋放的資料。

EventBase類是訊息實體類,可以看到上面所寫的就是通過send發訊息呼叫onNext,接收到訊息用訂閱者所在類的介面回撥過去,實現接收到訊息。

體驗了一把發現有問題,比如我在activity1 register了並跳轉到activity2同也register監聽,然後跳轉到activity3,銷燬activity2 並在activity3 send訊息 這是很會發現activity1和activity2都會受到訊息,明明activity被銷燬了,這怎麼回事?第二個問題就是,也不算問題 就是我想用類似EventBus註解方式接受訊息。

解決辦法:1、在activity 銷燬時 RxBus進行反註冊,這樣就需要在RxBus定義 private Map<String,Subscription> mSubscriptions = new HashMap<>();存放註冊的時候Subject subscribe返回的Subscription例項 可以通過Subscription取消訂閱。2、使用自定義註解

首先上程式碼:

Event註解

/**
 * Author KINCAI
 * .
 * description TODO
 * .
 * Time 2016-12-08 10:21
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Event {
    String value();
}

RxBus改進

**
 * Author KINCAI
 * .
 * description TODO
 * .
 * Time 2016-12-07 12:54
 */
public class RxBus {
    private final Subject<Object, Object>
            rxBus = new SerializedSubject<>(PublishSubject.create());
    private Map<String,Subscription> mSubscriptions = new HashMap<>();

    private RxBus() {
    }
    public static RxBus getInstance() {
        return RxBusInstance.instance;
    }


    private static class RxBusInstance{
        private static final RxBus instance = new RxBus();
    }

    public void send(EventBase eventBase){
        rxBus.onNext(eventBase);
    }
    public void register(final Object obj){
        if(obj == null)
            return;
        Subscription subscription = rxBus.observeOn(AndroidSchedulers.mainThread())
                .map(new Func1<Object, EventBase>() {
                    @Override
                    public EventBase call(Object s) {
                        return (EventBase) s;
                    }

                }).subscribe(new Action1<EventBase>() {
                    @Override
                    public void call(EventBase eventBase) {
                        RxBus.this.call(obj, eventBase);
                    }
                });
        putSubscription(obj, subscription);

    }

    private void call(Object obj, EventBase eventBase){
        Class<?> cls = obj.getClass();
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Event.class)) {
                Event event = method.getAnnotation(Event.class);
                String value = event.value();
                String tag = eventBase.getTag();
                try {
                    if (TextUtils.isEmpty(tag) || TextUtils.isEmpty(value)) {
                        method.setAccessible(true);
                        method.invoke(obj, eventBase);
                    } else {
                        if (tag.equals(value)) {
                            method.setAccessible(true);
                            method.invoke(obj, eventBase);
                        }
                    }

                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void unRegister(Object obj){
        if(obj == null)
            return;
        Subscription subscription = getSubscription(obj);
        if(subscription != null && !subscription.isUnsubscribed()){
            subscription.unsubscribe();
        }
    }

    private void putSubscription(Object obj,Subscription subscription){
        String className = obj.getClass().getName();
        for (Map.Entry<String, Subscription> entry : mSubscriptions.entrySet()) {
            if(className.equals(entry.getKey())){
                if(!entry.getValue().isUnsubscribed()){
                   entry.getValue().unsubscribe();
                }
                mSubscriptions.remove(className);
                break;
            }
        }
        mSubscriptions.put(className,subscription);
    }

    private Subscription getSubscription(Object obj){
        String className = obj.getClass().getName();
        for (Map.Entry<String, Subscription> entry : mSubscriptions.entrySet()) {
            if(className.equals(entry.getKey())){
                Subscription value = entry.getValue();
                mSubscriptions.remove(entry.getKey());
                return value;
            }
        }
        return null;
    }


    /*public interface EventListener {
        void onEvent(EventBase eventBase);
    }*/
}

訂閱者

@Event(EventNotify.MAIN_INIT)
    public void onEvent(EventBase eventBase) {
        LogUtils.e("event main "+eventBase.getTag());
        if(EventNotify.MAIN_INIT_RE_LOAD.equals(eventBase.getFlag())){
            clearRefreshUserInfo();
            initLoad();
        }
    }

傳送訊息不變

註冊的時候傳入object就是當前註冊類例項 用類名作為鍵 Subscription作為值存入map集合,當然啦需要判斷鍵是否存在防止多次註冊,反註冊的時候根據鍵找到Subscription並判斷沒有取消訂閱的時候進行取消訂閱。

在call方法中主要是根據當前註冊類找到Event註解方法 並且判斷EventBase的tag值和Event value值是否相同,相同就呼叫onEvent方法,起到篩選作用,當然傳送的時候EventBaseTag為空的時候或者Event value為空就不篩選,直接回調,EventBase的flag引數是給訂閱者onEvent方法接收到訊息進一步篩選型別的。

好啦,這是我在activity1註冊 並且onEvent的Event("mian"),activity2註冊 並onEvent的Event("mian2")

這是我在activity3傳送訊息 RxBus.getInstance().send(new EventBase("main","test","data"));

毫無疑問,activity1才能收到訊息。

別忘了在onDestory方法反註冊哦;

二、總結

僅供參考,有什麼地方寫的不好的 ,或者有錯誤,歡迎提出。