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
            rxBus = new SerializedSubject<>(PublishSubject.create());
    private Map 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() {
                    @Override
                    public EventBase call(Object s) {
                        return (EventBase) s;
                    }

                }).subscribe(new Action1() {
                    @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 = 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 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
            rxBus = new SerializedSubject<>(PublishSubject.create());
    private Map 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() {
                    @Override
                    public EventBase call(Object s) {
                        return (EventBase) s;
                    }

                }).subscribe(new Action1() {
                    @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 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 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方法反注册哦;

二、总结

仅供参考,有什么地方写的不好的 ,或者有错误,欢迎提出。




你可能感兴趣的:(Android开发,Android,RxJava,EventBus,RxJava事件通知)