EventBus 使用详解

来源:互联网 发布:中国出口构成 知乎 编辑:程序博客网 时间:2024/05/18 19:43

EventBus 使用详解


概述

EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化Android事件传递,这里的事件可以理解为消息。事件传递既可以用于Android四大组件间通讯,也可以用于异步线程和主线程间通讯等。

传统的事件传递方式包括:Handler、BroadcastReceiver、Interface回调等
相比之下EventBus代码简洁,使用简单,并将事件发布和订阅充分解耦。


三个名词

  • 事件Event: 又可成为消息,其实就是一个对象,可以是网络请求返回的字符串,也可以是某个开关状态等等。事件类型EventType是指事件所属的Class。
    事件分为一般事件和Sticky事件,相对于一般事件,Sticky事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件的最近一个Sticky事件。

  • 订阅者Subscriber: 订阅某种事件类型的对象,当有发布者发布这类事件后,EventBus会执行订阅者的onEvent函数,这个函数叫事件响应函数。订阅者通过register接口订阅某个事件类型,unregister接口退订。订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为0。

  • 发布者Publisher: 发布某事件的对象,通过post接口发布事件。


基本使用

自定义一个事件类

public class AnyEventType {     public AnyEventType(){} }

在要接受消息的页面注册

EventBus.getDefault().register(this);

接收消息的方法

@Subscribepublic void onEvent(AnyEventType event) {    /* Do something */};

发送消息

EventBus.getDefault().post(event);

取消注册

EventBus.getDefault().unregister(this);

例子

下面我们来实现一个具体的例子来介绍EventBus的基本使用。

在MainActivity中注册EventBus事件,并实现事件响应方法,当点击MainActivity中的按钮时跳转到SecondActivity,当点击SecondActivity中的按钮时向MainActivity发送Event事件,当MainActivity收到事件后,将事件内容显示在TextView中。

事件类Event

public class Event {    private String messgae;    public Event(String messgae) {        this.messgae = messgae;    }    public String getMessgae() {        return messgae;    }}

MainActivity

在OnCreate()函数中注册EventBus,在Ondestroy()函数中反注册。

public class MainActivity extends AppCompatActivity {    @Bind(R.id.btn_open)    Button mOpenBtn;    @Bind(R.id.tv_showinfo)    TextView mInfoTxt;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);        //注册        EventBus.getDefault().register(this);    }    /**     * 事件响应方法     * 接收消息     * @param event     */    @Subscribe(threadMode = ThreadMode.MAIN)    public void onEvent(Event event) {        String msg = event.getMessgae();        mInfoTxt.setText(msg);    }    //绑定点击事件    @OnClick(R.id.btn_open)    public void openSecondActivity(View view) {            Intent intent = new Intent(MainActivity.this, SecondActivity.class);            startActivity(intent);    }    @Override    protected void onDestroy() {        super.onDestroy();        //反注册        EventBus.getDefault().unregister(this);    }}

SecondActivity

public class SecondActivity extends AppCompatActivity {    @Bind(R.id.btn_post)    Button mPostBtn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        ButterKnife.bind(this);        mPostBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        //发送事件                        EventBus.getDefault().post(new Event("Just do it"));                    }                }).start();            }        });    }}

EventBus的事件订阅函数

类别

在上面的例子中,我们再注解@Subscribe(threadMode = ThreadMode.MAIN)中使用了ThreadMode.MAIN这个模式,表示该函数在主线程即UI线程中执行,实际上EventBus总共有四种线程模式,分别是:

  • ThreadMode.MAIN:表示无论事件是在哪个线程发布出来的,该事件订阅方法onEvent都会在UI线程中执行,这个在Android中是非常有用的,因为在Android中只能在UI线程中更新UI,所有在此模式下的方法是不能执行耗时操作的。

  • ThreadMode.POSTING:表示事件在哪个线程中发布出来的,事件订阅函数onEvent就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。

  • ThreadMode.BACKGROUND:表示如果事件在UI线程中发布出来的,那么订阅函数onEvent就会在子线程中运行,如果事件本来就是在子线程中发布出来的,那么订阅函数直接在该子线程中执行。

  • ThreadMode.AYSNC:使用这个模式的订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程来执行订阅函数。

例子

如何调用不同的订阅函数

我们在基本使用章节的例子上进行扩展,首先建立四个类:FirstEvent、SecondEvent、ThirdEvent、FourthEvent。

FirstEvent

public class FirstEvent {    private String messgae;    public FirstEvent(String messgae) {        this.messgae = messgae;    }    public String getMessgae() {        return messgae;    }}

SecondEvent

public class SecondEvent {    private String messgae;    public SecondEvent(String messgae) {        this.messgae = messgae;    }    public String getMessgae() {        return messgae;    }}

ThirdEvent

public class ThirdEvent{    private String messgae;    public ThirdEvent(String messgae) {        this.messgae = messgae;    }    public String getMessgae() {        return messgae;    }}

FourthEvent

public class FourthEvent{    private String messgae;    public FourthEvent(String messgae) {        this.messgae = messgae;    }    public String getMessgae() {        return messgae;    }}

然后在MainActivity中,增加四种模式的订阅函数

public class MainActivity extends AppCompatActivity {    private static final String TAG = "MainActivity";    @Bind(R.id.btn_open)    Button mOpenBtn;    @Bind(R.id.tv_showinfo)    TextView mInfoTxt;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);        //注册        EventBus.getDefault().register(this);    }    /**     * 事件响应方法     * @param event     */    @Subscribe(threadMode = ThreadMode.MAIN)    public void onEventMain(FirstEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventMain: " + event.getMessgae());    }    @Subscribe(threadMode = ThreadMode.POSTING)    public void onEventPosting(SecondEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventPosting: "+ event.getMessgae());    }    @Subscribe(threadMode = ThreadMode.BACKGROUND)    public void onEventBackgroud(ThirdEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventBackgroud: " + event.getMessgae());    }    @Subscribe(threadMode = ThreadMode.ASYNC)    public void onEventAsync(FourthEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventAsync: " + event.getMessgae());    }    //绑定点击事件    @OnClick(R.id.btn_open)    public void openSecondActivity(View view) {            Intent intent = new Intent(MainActivity.this, SecondActivity.class);            startActivity(intent);    }    @Override    protected void onDestroy() {        super.onDestroy();        //反注册        EventBus.getDefault().unregister(this);    }}

接下来在SecondActivity中增加四个按钮,分别发送不同类别的事件

public class SecondActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        ButterKnife.bind(this);    }    @OnClick(R.id.btn_post)    public void onPostA() {        EventBus.getDefault().post(new FirstEvent("FirstEvent"));    }    @OnClick(R.id.btn_post2)    public void onPostB() {        EventBus.getDefault().post(new SecondEvent("SecondEvent"));    }    @OnClick(R.id.btn_post3)    public void onPostC() {        EventBus.getDefault().post(new ThirdEvent("ThirdEvent"));    }    @OnClick(R.id.btn_post4)    public void onPostD() {        EventBus.getDefault().post(new FourthEvent("FourthEvent"));    }}

运行后,分别顺序点击SecondActivity的四个按钮,打印信息如下:

12-25 20:00:45.950 4111-4111/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventMain: FirstEvent12-25 20:00:47.528 4111-4111/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventPosting: SecondEvent12-25 20:00:48.882 4111-4352/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventBackgroud: ThirdEvent12-25 20:00:50.462 4111-4352/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventAsync: FourthEvent

由此可见,通过发布不同的事件类的实例,EventBus根据类的实例分别调用了不同的订阅函数来处理事件。

那么,当同一个类的实例有多个函数订阅时,结果会是怎样呢?答案是,这些函数都会执行。下面我们来验证一下,将MainActivity中订阅函数的参数都改为FirstEvent,代码如下

/**     * 事件响应方法     * @param event     */    @Subscribe(threadMode = ThreadMode.MAIN)    public void onEventMain(FirstEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventMain: " + event.getMessgae());    }    @Subscribe(threadMode = ThreadMode.POSTING)    public void onEventPosting(FirstEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventPosting: "+ event.getMessgae());    }    @Subscribe(threadMode = ThreadMode.BACKGROUND)    public void onEventBackgroud(FirstEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventBackgroud: " + event.getMessgae());    }    @Subscribe(threadMode = ThreadMode.ASYNC)    public void onEventAsync(FirstEvent event) {        String msg = event.getMessgae();        Log.i(TAG, "onEventAsync: " + event.getMessgae());    }

运行程序,点击SecondActivity的FirstEvent按钮,打印信息如下:

12-25 20:02:45.025 24779-24779/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventAsync: FirstEvent12-25 20:02:45.652 24779-24779/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventMain: FirstEvent12-25 20:02:46.156 24779-24963/com.github.sadaharusong.eventbusdemoI/MainActivity: onEventPosting: FirstEvent12-25 20:02:46.999 24779-24963/com.github.sadaharusong.eventbusdemo I/MainActivity: onEventBackgroud: FirstEvent

分析可知,当SecondActivity发送FirstEvent事件过来的时候,这个四个订阅函数会同时接收到这个事件并执行。

总结: 订阅函数的执行是根据参数中的事件类的类名来决定的。


PS

优先级

如果在两个类中订阅同一个Event,不加优先级,是都会收到消息么?如果加了优先级,优先级高的先收到,那优先级低的还会收到么?

/** Subscriber priority to influence the order of event delivery.* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of* delivery among subscribers with different {@link ThreadMode}s! */

根据源码的注释信息 订阅了就都会收到

如何设置订阅者的优先级呢?

//像这样设置优先级,默认是0,越大越先接收事件@Subscribe(threadMode = ThreadMode.MAIN, priority = 1000);
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 化妆师吧 男化妆师 化妆师有前途吗 化妆师的发展前景 婚礼化妆师价格表 婚礼化妆师 化妆师速成班 职业化妆师 化妆师培训资料 化妆师前途怎么样 中级化妆师 化妆师需要考证吗 婚礼化妆师多少钱 化妆师证书怎么考 有名化妆师 化妆师学费 结婚化妆师价格 怎么样成为化妆师 造型化妆师 化妆师学习班 化妆师在哪学 跟妆化妆师 化妆师证怎么考 化妆师工资高吗 化妆师进修班 命运化妆师 死人化妆师 时尚化妆师 知名化妆师 化妆师培训价格 影视化妆师工资多少 毛戈平化妆师培训学校 学化妆师要多少学费 化妆师职业资格证书 时尚造型师 商业化妆师 怎样成为明星化妆师 家用化妆柜图片 梳妆柜图片 化妆柜图片 化妆品柜