EventBus3.2详解和使用(二)

前言: 迷茫,本就是青春该有的样子,但不要让未来的你,讨厌现在的自己。

一、概述

  我们在上一篇文章中介绍了EventBus普通事件和粘性事件的使用,对EventBus也有了一个大概的了解,但是我们对事件和发布者订阅者的关系有没有弄清楚呢?继续来深入了解。

EventBus使用的是发布/订阅者模式:
在这里插入图片描述
发布者通过EventBus发布事件,订阅者通过EventBus订阅事件,当发布者发送事件时,订阅该事件的订阅者的事件处理方法将被调用。从图中看出,发布者发送一个事件时,则该事件将会同时传递给一个或多个该事件的订阅者。

什么是发布/订阅者模式?

订阅者(Subscriber)把自己想订阅的事件(Event)注册(register)到调度中心(EventBus),当发布者(Publisher)发布该事件到调度中心时,也就是该事件触发时,由调度中心统一调度订阅者注册到调度中心的处理代码(onEvent())。(发布/订阅者模式与观察者模式并不完全一样)

EventBus的三要素

● Event:     事件, 可以使任意类型;
● Publisher:  事件发布者,可以在任意线程中发布事件,一般情况,通过EventBus.getDefault()获取EventBus实例,通过post(Object event)发布事件;
● Subscriber: 事件订阅者,在EventBus3.0之前,订阅者的事件处理方法必须定义以onEvent开头的具体方法名,而在3.0之后方法名可以可以随意取,但是必须加上@Subscribe()注解,并且指定线程模式,默认为ThreadMode.POSTING

EventBus的几种线程模式

线程模式含义特点
POSTING默认线程,表示订阅者将在发布事件的同一线程中被调用适用于不需要主线程就可以在短时间内完成的简单任务,避免了线程切换,开销更小
MAIN表示在Android中,订阅者在Android主线程中被调用如果发布事件的线程是主线程,订阅者的事件处理函数将直接被调用。如果发布事件的线程不是主线程,则将事件加入主线程队列中,排队等待执行;因此这里不能进行耗时操作,注意不能阻塞主线程
MAIN_ORDERED表示在Android中,订阅者在Android主线程中被调用与MAIN不同的是,无论发布事件的线程是在哪个线程,事件都将发送到主线程队列总是排队等待传递。注意不能阻塞主线程
BACKGROUND表示在Android中,订阅者在后台线程中被调用,在Android中,如果发布线程不是主线程,订阅者的事件处理函数直接使用该线程,如果发布线程是主线程,那么事件处理函数会开启一个后台线程,有序分发事件,注意不能阻塞后台线程,这里不能进行UI操作;如果不是在Android上,总是使用一个后台线程
ASYNC表示无论发布线程是什么线程,订阅者都会创建一个新的子线程执行使用于耗时操作,尽量避免同时触发大量的耗时较长的异步操作,EventBus使用线程池高效的复用已经完成异步操作的线程。

那么说明POSTING模式的订阅者处理函数线程与发布线程一致,MAINMAIN_ORDERED模式的订阅者处理函数线程为主线程,BACKGROUNDASYNC模式的订阅者处理函数线程为后台线程。

二、项目实践

首先来回顾一下EventBus普通事件的几个步骤:
(1)定义事件对象,事件对象可以是任意java类型,没有特殊要求,比如String、int、自定义类等。

public class MessageEvent {
    public String name;
}

(2)在接收消息的页面的生命周期方法中注册和反注册事件。

//注册EventBus
EventBus.getDefault().register(this);
//注销EventBus
EventBus.getDefault().unregister(this);

(3)订阅者实现事件处理方法,也称为"订阅者方法",当发布对应事件类型时,该方法被调用。

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent message){
    //TODO 接收事件后Do something
}

(4)发布事件。

EventBus.getDefault().post(Object event);

2.1几种线程模式使用

线程模式主要是为了发布事件和处理事件之间的线程切换使用,首先来验证一下不同的线程模式处理事件在哪个线程,创建两个Activity,ModeReceiveActivity中注册EventBus并且实现订阅者事件处理函数,ModeSendActivity负责发布事件。

ModeReceiveActivity.java

/**
 * 几种线程模式
 * 注册并接收事件
 */
public class ModeReceiveActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "ModeReceiveActivity";
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mode_receive);

        findViewById(R.id.btn_skip).setOnClickListener(this);
        mTv_content = findViewById(R.id.tv_content);
        //1.注册事件
        EventBus.getDefault().register(this);
    }

    //3.订阅者的接收事件处理函数

    //处理函数执行线程与发布线程一致
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onMessageEventPosting(String str) {
        //TODO 接收事件后Do something
        mTv_content.setText("onMessageEvent:" + str);
        Log.e(TAG, "onMessageEventPosting:" + Thread.currentThread().getName());
    }

    //处理函数执行线程为主线程
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEventMain(String str) {
        Log.e(TAG, "onMessageEventMain:" + Thread.currentThread().getName());
    }

    //处理函数执行线程为主线程
    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMessageEventMainOrdered(String str) {
        Log.e(TAG, "onMessageEventMainOrdered:" + Thread.currentThread().getName());
    }

    //处理函数执行线程为后台线程
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEventBackground(String str) {
        Log.e(TAG, "onMessageEventBackground:" + Thread.currentThread().getName());
    }

    //处理函数执行线程为后台线程
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onMessageEventAsync(String str) {
        Log.e(TAG, "onMessageEventAsync:" + Thread.currentThread().getName());
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_skip://跳转到ModeSendActivity
                startActivity(new Intent(this, ModeSendActivity.class));
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //2.反注册事件
        EventBus.getDefault().unregister(this);
    }
}

ModeReceiveActivity作为接受消息的页面,是订阅者,首先在在onCreate()注册EventBus,onDestroy()中反注册,并且实现几种线程模式的订阅者的事件处理函数,将接收数据的线程通过Thread.currentThread().getName()线程名字打印log,点击按钮跳转到ModeSendActivity发布者中在主线程发布事件。
ModeSendActivity.java

/**
 * 几种线程模式
 * 发送事件
 */
public class ModeSendActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mode_send);
        findViewById(R.id.btn_send).setOnClickListener(this);
        mTv_content = findViewById(R.id.tv_content);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_send://发布事件
                mTv_content.setText("对ModeReceiveActivity发布事件");
                //4.发布事件
                EventBus.getDefault().post("接收到ModeSendActivity发送过来的事件啦");
                break;
        }
    }
}

点击发布事件按钮ModeSendActivity给ModeReceiveActivity发送事件,这里发布的线程是主线程。打印数据如下:
在这里插入图片描述
可以看到,POSTING模式的线程与发布线程一致,都是主线程;MAINMAIN_ORDERED模式的线程为主线程,BACKGROUNDASYNC模式线程为后台线程。(源码在文章最后给出)

2.2事件的优先级

EventBus支持定义订阅者事件处理方法时指定事件传递的优先级。默认情况下,事件优先级为0,数值越大,优先级越高,在相同线程模式下,优先级高的比优先级低的先接收到事件。

注意:优先级只有在相同线程模式下才有效。

	@Subscribe(threadMode = ThreadMode.MAIN, priority = 0)
    public void onMessageEvent(String str) {
        //TODO 接收事件后Do something
    }

● priority :     事件优先级, int类型,默认为0;数值越大,优先级越高,在相同线程模式下,优先级高的比优先级低的先接收到事件。

我们来创建两个Activity检验一下,PriorityReceiveActivity实现订阅者的事件处理方法,不同优先级的多个方法,PrioritySendActivity负责发布事件。
PriorityReceiveActivity.java

/**
 * 事件优先级
 * 注册并接收事件
 */
public class PriorityReceiveActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "PriorityReceiveActivity";
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_priority_receive);
        findViewById(R.id.btn_skip).setOnClickListener(this);
        mTv_content = findViewById(R.id.tv_content);
        
        //1.注册事件
        EventBus.getDefault().register(this);
    }

    //3.订阅者的接收事件处理函数, 事件优先级0,1,2
    @Subscribe(threadMode = ThreadMode.MAIN, priority = 0)
    public void onMessageEvent(String str) {
        //TODO 接收事件后Do something
        mTv_content.setText("onMessageEvent:" + str);
        Log.e(TAG, "onMessageEvent:priority = 0 " + str);
    }

    @Subscribe(threadMode = ThreadMode.MAIN, priority = 1)
    public void onMessageEvent1(String str) {
        Log.e(TAG, "onMessageEvent:priority = 1 "+str);
    }

    @Subscribe(threadMode = ThreadMode.MAIN, priority = 2)
    public void onMessageEvent2(String str) {
        Log.e(TAG, "onMessageEvent:priority = 2 " + str);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_skip://跳转到PrioritySendActivity
                startActivity(new Intent(this, PrioritySendActivity.class));
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //2.反注册事件
        EventBus.getDefault().unregister(this);
    }
}

这里定义了priority = 0,1,2三个优先级的处理函数,在onCreate()注册EventBus,onDestroy()中反注册,点击按钮跳转到PrioritySendActivity中;

/**
 * 事件优先级
 * 发送事件
 */
public class PrioritySendActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_priority_send);
        findViewById(R.id.btn_send).setOnClickListener(this);
        mTv_content = findViewById(R.id.tv_content);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_send://发布事件
                mTv_content.setText("对PriorityReceiveActivity发布事件");
                //4.发布事件
                EventBus.getDefault().post("接收到PrioritySendActivity发送过来的事件啦");
                break;
        }
    }
}

点击发布事件按钮,给PriorityReceiveActivity发布事件,接收到数据,效果如下:

打印log如下:
在这里插入图片描述
从数据可以看到,优先级priority = 0<1<2,优先级高的比优先级低的先接收到数据。(源码在文章最后给出)

三、AndroidEventBus的使用

  发布者发送一个事件时,则该事件将会同时传递给一个或多个该事件的订阅者。如果发布事件的事件对象类型与订阅者处理事件方法对象类型匹配,那么匹配的所有已注册的事件都会接收到。

	//发布事件
	EventBus.getDefault().post(new MessageEvent());
		
	//多个接收事件处理的函数
	//接收Activity1事件处理
	@Subscribe(threadMode = ThreadMode.MAIN)
	public void onMessageEventActivity1(MessageEvent message) {
   		//TODO 接收事件后Do something  
   		Log.e(TAG, "onMessageEventActivity1 ==");   
	}

	//接收Activity2事件处理
	@Subscribe(threadMode = ThreadMode.MAIN)
	public void onMessageEventActivity2(MessageEvent message) {
   		//TODO 接收事件后Do something
   		Log.e(TAG, "onMessageEventActivity2 ==");    
	}

onMessageEventActivity1()onMessageEventActivity2()都在同一个Activity中订阅事件,但是发布者来自不同的Activity,发布事件post(Object event)方法中的event的类型与处理事件onMessageEvent(Object event)中event的类型一致的话,都会接收到发布的数据。打印数据如下:
在这里插入图片描述
当然我们可以指定不同的事件对象类型,或者在事件对象类型添加标志区分,比如在MessageEvent中添加type区分不同。但是如果都是事件对象类型都是String那就区分不了。

3.1AndroidEventBus

我们可以使用AndroidEventBus,EventBus是AndroidEventBus框架的核心类,也是用户的入口类。它存储了用户注册的订阅者信息和方法,事件类型和该事件对应的tag标识一个种类的事件EventType,每一种事件对应有一个或者多个订阅者,订阅者中的订阅函数通过@Subscriber注解来标识tag和线程模型,这样使得用户体检较为友好,代码也更加整洁。

AndroidEventBus与EventBus不同的是,多了一种该事件对应的tag标识和订阅者中的订阅函数通过@Subscriber注解(EventBus的是@Subscribe)。

	//发布者发布事件,tag为from_three
	EventBus.getDefault().post(new MessageEvent("接收到AndroidBusSendActivity发送过来的事件啦"), "from_three");
	
	//订阅者的事件处理函数, 有tag为from_three
    @Subscriber(tag = "from_three", mode = ThreadMode.MAIN)
    public void eventAndroidEventBus(MessageEvent message) {  
    }

● post(Object event, String tag): 发布者发布事件的方法;event表示要发布的事件,任意类型;tag表示事件的标识,用于区分其他事件,String类型(区分大小写);
●@Subscriber:必须使用@Subscriber注解来定义订阅者方法,否则事件处理方法无法生效。与EventBus的@Subscribe类同;
●tag :       tag表示事件的标识,用于区分其他事件。与发布事件的tag相对应;
●mode :     线程模式,表示在哪个线程里面执行。与EventBus的threadMode类同。

3.2AndroidEventBus普通事件

AndroidEventBus与EventBus的用法大致相同,首先在build.gradle文件中添加依赖:

implementation 'org.simple:androideventbus:1.0.5.1'

然后创建两个Activity,AndroidBusSendActivity发布者发布事件,AndroidBusReceiveActivity在onCreate()onDestroy()中注册反注册事件,实现不同tag的多个订阅者事件处理方法。

注意,需要使用AndroidEventBus的包org.simple.eventbus

AndroidBusReceiveActivity.java

import org.simple.eventbus.EventBus;
import org.simple.eventbus.Subscriber;
import org.simple.eventbus.ThreadMode;
/**
 * AndroidEventBus
 * 接收消息页面
 */
public class AndroidBusReceiveActivity extends AppCompatActivity implements View.OnClickListener{
	public static final String TAG = "AndroidEventBus";
    private TextView mTv_content, mTv_content2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_receive);

        findViewById(R.id.btn_skip).setOnClickListener(this);
        mTv_content = findViewById(R.id.tv_content);
        mTv_content2 = findViewById(R.id.tv_content2);

        //1.注册事件
        EventBus.getDefault().register(this);
    }

    //3.接收事件处理, 有tag为from_three
    @Subscriber(tag = "from_three", mode = ThreadMode.MAIN)
    public void eventAndroidEventBus(MessageEvent message) {
        mTv_content2.setText("eventAndroidEventBus: tag = from_three | " + message.name);
        Log.e(TAG, "eventAndroidEventBus ==  tag = from_three | " + message.name);
    }

    //接收事件处理,有tag为FROM_THREE
    @Subscriber(tag = "FROM_THREE", mode = ThreadMode.MAIN)
    public void eventAndroidEventBus1(MessageEvent message) {
       mTv_content.setText("eventAndroidEventBus: tag = FROM_THREE | " + message.name);
       Log.e(TAG, "eventAndroidEventBus1 ==  tag = FROM_THREE | " + message.name);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //2.反注册事件
        EventBus.getDefault().unregister(this);
    }
}

AndroidBusSendActivity.java

import org.simple.eventbus.EventBus;
/**
 * AndroidEventBus
 * 发送消息页面
 */
public class AndroidBusSendActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_send);
        findViewById(R.id.btn_send).setOnClickListener(this);
        mTv_content = findViewById(R.id.tv_content);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_send://发布事件
                mTv_content.setText("对AndroidBusReceiveActivity发布事件");
                //4.发布事件,tag为from_three
                EventBus.getDefault().post(new MessageEvent("接收到AndroidBusSendActivity发送过来的事件啦"), "from_three");
                break;
            default:
                break;
        }
    }
}

效果如下:

打印数据如下:
在这里插入图片描述
可以看到,即使事件类型一致,但是只有发布事件和订阅函数处理的tag相同才能接收到事件。

3.3AndroidEventBus的粘性事件

粘性事件能在发送事件之后再订阅该事件也能接收到该事件。与普通事件不同,普通事件是先注册后发布,粘性事件可以先发布后注册。AndroidEventBus的粘性事件的使用与EventBus的粘性事件有点不一样,AndroidEventBus需要注册粘性事件,订阅者的事件处理函数不需要添加sticky标识。来看看AndroidEventBus的粘性事件的使用步骤:

(1) 在onCreate()中注册粘性事件registerSticky()onDestroy()中反注册事件。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //1.注册粘性事件
        EventBus.getDefault().registerSticky(this);
    }
    
  	@Override
    protected void onDestroy() {
        super.onDestroy();
        //2.反注册事件
        EventBus.getDefault().unregister(this);
    }

(2) 订阅者的事件处理函数。

  //3.接收粘性事件处理, 有tag为from_android_sticky
    @Subscriber(tag = "from_android_sticky", mode = ThreadMode.MAIN)
    public void eventAndroidEventBus(String message) {
        Log.e(TAG, "eventAndroidEventBus ==  tag = from_android_sticky | " + message);

        //5.移除粘性事件
        EventBus.getDefault().removeStickyEvent(String.class, "from_android_sticky");
    }

注意:如果不需要粘性事件了通过抽象removeStickyEvent()及时移除粘性事件。

(3) 发布者发布粘性事件postSticky()

//4.发布粘性事件,tag为from_android_sticky 
EventBus.getDefault().postSticky("接收到AndroidStickySendActivity发送过来的事件啦", "from_android_sticky");

粘性事件主要步骤就是这几个,我们来验证一下,创建两个Activity,AndroidStickySendActivity先布粘性事件然后再跳转AndroidStickyReceiveActivity,AndroidStickyReceiveActivity创建并注册EventBus后接收到粘性事件消息。

/**
 * AndroidEventBus粘性事件
 * 发送消息页面
 */
public class AndroidStickySendActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_send_sticky);
        findViewById(R.id.btn_send).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_send://发布事件
                //4.发布粘性事件,tag为from_three
                EventBus.getDefault().postSticky("接收到AndroidStickySendActivity发送过来的事件啦", "from_android_sticky");
                startActivity(new Intent(this, AndroidStickyReceiveActivity.class));
                break;
        }
    }
}

AndroidStickySendActivity中点击发布粘性事件按钮,给AndroidStickyReceiveActivity发送事件,再跳转到AndroidStickyReceiveActivity中。

/**
 * AndroidEventBus粘性事件
 * 接收消息页面
 */
public class AndroidStickyReceiveActivity extends AppCompatActivity {
    public static final String TAG = "StickyReceiveActivity";
    private TextView mTv_content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_receive_sticky);
        mTv_content = findViewById(R.id.tv_content);

        //1.注册粘性事件
        EventBus.getDefault().registerSticky(this);
    }

    //3.接收粘性事件处理, 有tag为from_three
    @Subscriber(tag = "from_android_sticky", mode = ThreadMode.MAIN)
    public void eventAndroidEventBus(String message) {
        mTv_content.setText("eventAndroidEventBus ==  tag = from_android_sticky | " + message);
        Log.e(TAG, "eventAndroidEventBus ==  tag = from_android_sticky | " + message);

        //5.移除粘性事件
        EventBus.getDefault().removeStickyEvent(String.class, "from_android_sticky");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //2.反注册事件
        EventBus.getDefault().unregister(this);
    }
}

AndroidStickyReceiveActivity完成创建并注册EventBus,实现订阅者的粘性事件处理方法,接收到发送过来的粘性事件数据,效果如下:

打印数据如下:
在这里插入图片描述
注意:发送事件的参数类型一定要与接收事件的参数类型一致啊,否则无法接收到事件的。

源码地址

点关注,不迷路


好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才

我是suming,感谢各位的支持和认可,您的点赞、评论、收藏【一键三连】就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

要想成为一个优秀的安卓开发者,这里有必须要掌握的知识架构,一步一步朝着自己的梦想前进!Keep Moving!


相关文章:

EventBus3.2详解和使用(一)

 ● EventBus:普通事件和粘性事件的使用

EventBus3.2详解和使用(二)

 ● EventBus三要素、线程模式、优先级和AndroidEventBus的使用

EventBus3.2详解和使用(三)

 ● EventBus内部原理

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值