EventBus 使用123

EventBus是针一款对Android的发布/订阅事件总线。它简化了应用程序内各组件间、组件与后台线程间的通信,并且代码的可读性更好,耦合度更低。比如请求网络、Activity和Servie、Fragment之间的通信,这些需求都可以通过EventBus实现。

EventBus采用的是发布/订阅设计模式,主要包含三个元素:
- Event:事件
- Subscriber:事件订阅者,接收特定的事件
- Publisher: 事件发布者,用于通知Subscriber有事件发生

如何使用

EventBus的简单使用,如下代码1-5步骤所示

//1、首先需要定义一个消息类,该类可以不继承任何基类也不需要实现任何接口。
public class MsgEvent {
    private String msg;

    public MsgEvent(String msg) {
        this.msg = msg;
    }
}

public class MainActivity extends AppCompatActivity {
    Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtn = (Button) findViewById(R.id.btn);
        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MsgEvent msgEvent = new MsgEvent("hello world");
                EventBus.getDefault().post(msgEvent);//3、产生事件,即发送消息
            }
        });

        EventBus.getDefault().register(this);//2、在需要订阅事件的Activity注册事件
    }

    //5、将EventBus绑定到Activity的生命周期中
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//取消消息订阅
    }

    //4、处理事件的方法,这里需要添加一个注解@Subscribe,并且要指定线程,这里是UI主线程
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(MsgEvent msgEvent) {
        Log.e("ThreadName", Thread.currentThread().getName());
        Log.e("msgEvent", msgEvent.getMsg());
    }
}

在3.0之前,EventBus还没有使用注解方式。消息处理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分别代表四种线程模型。而在3.0之后,消息处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为PostThread),四种线程模型,下面会讲到。所定义的事件处理方法,访问权限需要为public,否则会报异常,但是自己用protected测试好像也可以,还没有找到原因,以后再分析吧。

EventBus 线程模型

在EventBus的事件处理函数中需要指定线程模型,即指定事件处理方法运行所在的想线程。EventBus中的观察者通常有四种线程模型:分别是PostThread(默认)、MainThread、BackgroundThread与Async。

  • PostThread:如果使用事件处理函数指定了线程模型为PostThread,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为PostThread的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
  • MainThread:如果使用事件处理函数指定了线程模型为MainThread,那么不论事件是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。该方法可以用来更新UI,但是不能处理耗时操作。
  • BackgroundThread:如果使用事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
  • Async:如果使用事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。同样,此事件处理函数中禁止进行UI更新操作。

下面用例子来验证一下

mBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e("ThreadName when post event",Thread.currentThread().getName());
                MsgEvent msgEvent = new MsgEvent("hello world");
                EventBus.getDefault().post(msgEvent);//在一个新线程中发送消息事件
            }
        }).start();
    }
});


@Subscribe(threadMode = ThreadMode.MAIN)
protected void onEventMainThread(MsgEvent msgEvent) {
    Log.e("ThreadName", Thread.currentThread().getName());
    Log.e("Main-msgEvent", msgEvent.getMsg());
}

@Subscribe(threadMode = ThreadMode.POSTING)
protected void onEventPostThread(MsgEvent msgEvent) {
    Log.e("ThreadName", Thread.currentThread().getName());
    Log.e("Post-msgEvent", msgEvent.getMsg());
}

@Subscribe(threadMode = ThreadMode.BACKGROUND)
protected void onEventBackgroundThread(MsgEvent msgEvent) {
    Log.e("ThreadName", Thread.currentThread().getName());
    Log.e("Background-msgEvent", msgEvent.getMsg());
}

@Subscribe(threadMode = ThreadMode.ASYNC)
protected void onEventAsyncThread(MsgEvent msgEvent) {
    Log.e("ThreadName", Thread.currentThread().getName());
    Log.e("Async-msgEvent", msgEvent.getMsg());
}

打印结果如下:

09-02 03:08:41.066 13742-13891/lyri.example E/ThreadName when post event: Thread-177
09-02 03:08:41.067 13742-13891/lyri.example E/Back-ThreadName: Thread-177
09-02 03:08:41.067 13742-13891/lyri.example E/Post-ThreadName: Thread-177
09-02 03:08:41.072 13742-13892/lyri.example E/Async-ThreadName: pool-1-thread-1
09-02 03:08:41.076 13742-13742/lyri.example E/Main-ThreadName: main

发送黏性事件
除了上面讲的普通事件外,EventBus还支持发送黏性事件。他跟黏性广播类似,就是在发送事件之后再订阅该事件也能收到该事件。
和普通事件相比,在使用上就2个区别:
1)发送

EventBus.getDefault().postSticky(msgEvent);

2)注册事件处理方法,添加一个属性sticky=true

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
protected void onEventMainThread(MsgEvent msgEvent) {
    Log.e("Main-ThreadName", Thread.currentThread().getName());
}

例子

mPostBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        count++;//表示发送了几次粘性事件
        MsgEvent msgEvent=new MsgEvent("hello world"+count);
        Log.e("post a event in thread %s",Thread.currentThread().getName());
        EventBus.getDefault().postSticky(msgEvent);
    }
});

@Override
protected void onDestroy() {
    super.onDestroy();
    EventBus.getDefault().unregister(this);
}

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
protected void onEventMainThread(MsgEvent msgEvent) {
    Log.e("Main-msgEvent", msgEvent.getMsg());
}

@Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
protected void onEventPostThread(MsgEvent msgEvent) {
    Log.e("Post-msgEvent", msgEvent.getMsg());
}

@Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true)
protected void onEventBackgroundThread(MsgEvent msgEvent) {
    Log.e("Background-msgEvent", msgEvent.getMsg());
}

@Subscribe(threadMode = ThreadMode.ASYNC,sticky = true)
protected void onEventAsyncThread(MsgEvent msgEvent) {
    Log.e("Async-msgEvent", msgEvent.getMsg());
}

如果发送5次粘性事件后,Activity再注册EventBus,打印结果:

09-02 03:25:42.849 2326-2326/lyri.example E/Main-msgEvent: hello world5
09-02 03:25:42.849 2326-2509/lyri.example E/Async-msgEvent: hello world5
09-02 03:25:42.849 2326-2326/lyri.example E/Post-msgEvent: hello world5
09-02 03:25:42.851 2326-2510/lyri.example E/Background-msgEvent: hello world5

虽然发送了5次粘性事件,但是它只收到最新的一次消息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值