EventBus封装

作者: xiaoyanger | 来源:发表于2017-05-11 14:59 被阅读2297次

    EventBus是一款针对Android优化的发布/订阅事件总线。可以替代广播、startActivityForResultHandler、异步回调等来实现各组件间、组件与后台线程间的通信。它的优点是开销小,代码更优雅,以及将发送者和接收者解耦。

    通常我们在使用EventBus的时候都是直接需要接收通信的Activity/Fragment中通过EventBus.getDefault().register(this)订阅事件,在需要发起通信的逻辑直接调用EventBus.getDefault().post(Object event)来发布事件。但是要是一个项目中有很多地方都使用EventBus来通信,比如重新登录后更新各个页面的登录状态,或者是接收到通知更新消息提示等,都这样直接使用的话代码重复率很高,并且呢,如果以后升级或者更换EventBus时,各个地方都要修改,这就比较麻烦了。因此我一般是将EventBus的发布和订阅封装到BaseActivity/BaseFragment中。

    在Gradle中添加EventBus依赖:

    compile 'org.greenrobot:eventbus:3.0.0'
    

    封装一下EventBus的订阅、取消订阅、发布等方法:

    public class EventBusUtil {
    
        public static void register(Object subscriber) {
            EventBus.getDefault().register(subscriber);
        }
    
        public static void unregister(Object subscriber) {
            EventBus.getDefault().unregister(subscriber);
        }
    
        public static void sendEvent(Event event) {
            EventBus.getDefault().post(event);
        }
        
        public static void sendStickyEvent(Event event) {
            EventBus.getDefault().postSticky(event);
        }
    
        // 其他
    }
    

    BaseActivity/BaseFragment中的onCreateonDestroy方法中订阅和取消订阅,这里添加了一个isRegisterEventBus()方法,默认返回false,即不订阅EventBus,子类Activity/Fragment如果需要订阅的话复写这个方法并返回true即可。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (isRegisterEventBus()) {
            EventBusUtil.register(this);
        }
    }
    
    /**
     * 是否注册事件分发
     *
     * @return true绑定EventBus事件分发,默认不绑定,子类需要绑定的话复写此方法返回true.
     */
    protected boolean isRegisterEventBus() {
        return false;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (isRegisterEventBus()) {
            EventBusUtil.unregister(this);
        }
    }
    

    定义事件Event

    public class Event<T> {
        private int code;
        private T data;
    
        public Event(int code) {
            this.code = code;
        }
    
        public Event(int code, T data) {
            this.code = code;
            this.data = data;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    

    通过泛型<T>指定事件通信过程中的数据类型,code为事件码,使用的时候给不同的事件类型指定不同的code

    BaseActivity\BaseFragment中添加接收到EventBus的方法:

    /**
     * 是否注册事件分发
     *
     * @return true绑定EventBus事件分发,默认不绑定,子类需要绑定的话复写此方法返回true.
     */
    protected boolean isRegisterEventBus() {
        return false;
    }
    
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventBusCome(Event event) {
        if (event != null) {
            receiveEvent(event);
        }
    }
    
    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onStickyEventBusCome(Event event) {
        if (event != null) {
            receiveStickyEvent(event);
        }
    }
    
    /**
     * 接收到分发到事件
     *
     * @param event 事件
     */
    protected void receiveEvent(Event event) {
    
    }
    
    /**
     * 接受到分发的粘性事件
     *
     * @param event 粘性事件
     */
    protected void receiveStickyEvent(Event event) {
    
    }
    

    根据自己项目的需求,在订阅了EventBusActivity/Fragment中复写receiveEvent(Event event)receiveStickyEvent(Event event)来处理接收到事件后的逻辑。

    这里也可以不用在BaseActivty/BaseFragment中添加接受事件的方法(因为添加了过后不能确定的子类的Event泛型)。那么就直接在订阅的Activity/Fragment中给接收事件的方法添加EventBus对应的事件接受注解,并指定参数Event的泛型。

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventReceived(Event<User> event) {
        if (event != null && event.getCode() == C.EventCode.C) {
            User user = event.getData();
        }
    }
    

    在给定Eventcode的时候最好在常量池中定义一个类专门用来定义不同类型的EventBuscode,这样在接收到EventBus的地方可以根据这些code值来判断Event的来源。

    public final class C {
        // EventBus Code
        public static final class EventCode {
            public static final int A = 0x111111;
            public static final int B = 0x222222;
            public static final int C = 0x333333;
            public static final int D = 0x444444;
            // other more
        }
    }
    

    使用示例:
    MainActivity中复写isRegisterEventBus()并返回true注册EventBus,复写receiveEvent(Event event)接收发布的事件。

    @Override
    protected boolean isRegisterEventBus() {
        return true;
    }
    
    @Override
    protected void receiveEvent(Event event) {
        // 接受到Event后的相关逻辑
        switch (event.getCode()) {
            case C.EventCode.A:
                Log.d("EventBus", "接收到A类型的Event");
                break;
            case C.EventCode.B:
                Log.d("EventBus", "接收到B类型的Event");
                break;
            case C.EventCode.C:
                Log.d("EventBus", "接收到B类型的Event,携带User");
                User user = (User) event.getData();
                break;
            case C.EventCode.D:
                Log.d("EventBus", "接收到D类型的Event,携带News");
                News news = (News) event.getData();
                break;
        }
    }
    

    receiveEvent(Event event)根据对应的事件的code,判断通信的数据来源和传递的数据类型,以完成对应的逻辑。

    InfoActivity中发送事件,InfoActivity只发送不需要接收Event的话就不注册,也不用复写isRegisterEventBus()receiveEvent(Event event)方法了。

    public void sendEventA(View view) {
        EventBusUtil.sendEvent(new Event(C.EventCode.A));
    }
    
    public void sendEventB(View view) {
        EventBusUtil.sendEvent(new Event(C.EventCode.B));
    }
    
    public void sendEventC(View view) {
        Event<User> event = new Event<>(C.EventCode.C, new User());
        EventBusUtil.sendEvent(event);
    }
    
    public void sendEventD(View view) {
        Event<News> event = new Event<>(C.EventCode.D, new News());
        EventBusUtil.sendEvent(event);
    }
    

    通过上面的方式,将EventBus封装到BaseActivity/BaseFragment中,使得EventBus和项目解耦更加彻底,同时在需要使用的子Activity/Fragment中只需要复写isRegisterEventBus()receiveEvent(Event event)即可,不用每个地方都去订阅和取消订阅。并且给Event给定code和泛型能够很好的区分不同的事件来源和数据类型。


    源码:https://github.com/xiaoyanger0825/EventBusExample

    相关文章

      网友评论

      • 4d226614f116:我想问一下如何传递数据/
      • JohnsonZZZ:哈哈,不得不说很多想法想到一块去了😀 和我在项目的封装神似。不过文中有一点可以继续优化的地方,关于event code你采用了全局静态常量作为区分,大量使用后,这样会增加一些内存占用,建议直接采用另外方式,比如A界面传递数据到B界面并且做了一个操作fun()。code就是"A2B_fun()"
      • 有点健忘:解耦思想不错,这个eventbus我一直用的洪洋那个封装的,直接可以post一个对象的。原生的基本没用过。
        DevSpoon:@有点健忘 你这是一个人么...
        有点健忘:@wo叫天然呆
        https://github.com/hehonghui/AndroidEventBus
        代码比较老。哎,我也是用了2年拉。^_^。一直懒得换。关键原生的貌似不能直接post一个对象过去不爽
        wo叫天然呆:鸿洋大神也有封装么?能提供下地址么?
      • 78983551cc90:Eventbus少用, Activity意外销毁他无法恢复数据. 而且界面传递都要用粘性事件我觉得很消耗性能

      本文标题:EventBus封装

      本文链接:https://www.haomeiwen.com/subject/gufotxtx.html