EventBus

1. 引入EventBus

implementation 'org.greenrobot:eventbus:3.1.1'

2. 注册和注销EventBus

//注册位置:onCreate 或者 onStart
EventBus.getDefault().register(object);

//不使用的时候记得unregister onDestroy 或者 onStop
EventBus.getDefault().unregister(object);

3. 订阅或者发布事件

//注册的object内部实现
//func 函数名称,用户自己定义 
//T event ,T 表示某个类型事件,T可以是基本类型,也可以是class,不同的类表示不同的事件(注意继承关系)
//threadMode  不同,响应行为不一样,后面解释
@Subscribe(threadMode = ThreadMode.MAIN)
public void func(T event ){};

//发布事件,一般使用Post,稍后讲解postSticky
//调用post方法的时候,如果订阅者和post在同一线程则post将等所有消费者完成之后返回。
//如果不在同一线程则将事件投递到pendingqueue的队列
//(mainThreadPoster,backgroundPoster,asyncPoster)里面去之后再去触发事件。
EventBus.getDefault().post(T event);

//事件订阅者在事件发布之后注册的也能接收到该事件的特殊类型,订阅者必须指定sticky = true
//只保留最后一个sticky事件
//@Subscribe(sticky = true,threadMode = ThreadMode.MAIN_ORDERED)
//public void func(T event ){};
EventBus.getDefault().postSticky(T event);

4. ThreadMode 的五种模式

  • ThreadMode.MAIN

    • 订阅者方法将在主线程(UI线程)中被调用
    • 如果发布事件的线程是主线程,那么该模式的订阅者方法将被直接调用否则进入队列
    • 使用该模式的订阅者方法必须快速返回,不应该做耗时的操作,以避免阻塞主线程(如果主线程是Poster)
  • ThreadMode.MAIN_ORDERED

    • 订阅者方法将在主线程(UI线程)中被调用
    • 事件将先进入队列然后才发送给订阅者,所以发布事件的调用将立即返回
    • 使用该模式的订阅者方法必须快速返回,不应该做耗时的操作,以避免阻塞主线程(如果主线程是Poster)
    • 不同的线程发送消息,先加入队列的会优先执行
  • ThreadMode.BACKGROUND

    • 每一个订阅者方法将在后台同一个线程中被调用
    • 如果发布事件的线程不是主线程,那么订阅者方法将直接在该线程中被调用
    • 如果发布事件的线程是主线程,那么将使用一个单独的后台线程,该线程将按顺序发送所有的事件
  • ThreadMode.POSTING

    • 默认的线程模式
    • 订阅者将在发布者的线程中被调用(同步的,只有所有订阅者处理完成之后post才返回)
  • ThreadMode.ASYNC

    • 保证每个订阅者方法将在一个独立的子线程中被调用
    • 发布事件的调用将立即返回
    • 避免触发大量的长时间运行的订阅者方法,以限制并发线程的数量
    • EventBus使用了一个线程池来有效地重用已经完成调用订阅者方法的线程。

配合下面部分post调度源码将更加清楚(invokeSubscriber直接在当前线程调用)。

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

5. 多继承的子类订阅事件分析(以String为例)

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    ....
    }

EventBsu.java

 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
 		//获取Event的Class
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
        	//获取Event的所有父类
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            //投递所有父类Event
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
        }
       ...
       }

此时注意eventTypes 的size和值

在这里插入图片描述

所以如果我们订阅了以上五种class,那么 EventBus.getDefault().post(String);将被以上订阅者接受。至于接受顺序和ThreadMode相关。eg:ThreadMode.MAIN_ORDERED,那么订阅者顺序则为String->Serializable->Comparable->CharSequence->Object即:Sting的继承顺序。
在这里插入图片描述

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(String event) {
        Log.i("", "Subscribe Recv String Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(Serializable event)  {
        Log.i("", "Subscribe Recv Serializable Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(Comparable event) {
        Log.i("", "Subscribe Recv Comparable Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(CharSequence event) {
        Log.i("", "Subscribe Recv CharSequence Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(Object event) {
        Log.i("", "Subscribe Recv Object Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

6. ASYNC 模式保证每个订阅者都是独立的线程和是否多继承没关系
在这里插入图片描述

6. BACKGROUND 每一个订阅者方法将在后台同一个线程中被调用
在这里插入图片描述
在这里插入图片描述
7. 订阅者不同类型情景
1.进入队列顺序:多继承:子类->父类继承顺序。eg:String->Serializable->Comparable->CharSequence->Object
2.进入队列情况,根据不同订阅类型来决定。
3.执行顺序根据线程的cpu调度决定。

eg:以在UI线程Post(String)t为例,分析下列事件调用线程和执行顺序情况。

	//进入UI线程队列
    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(String event) {}
	
	//不进入队列,直接执行,所以会优先于事件String 执行
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMainModeEvent(Serializable event)  {}
	
	//不进入队列,直接执行,由于Comparable 顺序在Serializable 后面,所以会优先
	//事件String 执行d但是在事件Serializable 之后执行,该事件执行完成之后Post返回。
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onMainModeEvent(Comparable event) {}
	
	//进入后台线程,执行顺序由cpu调度决定
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMainModeEvent(CharSequence event) {}
	
	//进入后台线程,执行顺序由cpu调度决定
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onMainModeEvent(Object event) {}

上述事件将在三个线程中完成,分别是UI,thread1,thread2.每个线程中的执行内容和顺序如下:
UI

  1. Serializable 事件
  2. Comparable 事件
  3. String 事件

thread1

  1. CharSequence 事件

thread2

  1. Object 事件

在这里插入图片描述

7. postSticky

  • postSticky
    • 只保留最后一个投递的消息
    • 凡是在该事件投递之后注册的Object依然可以接受到Event,不论该Event是否被其他订阅过

SecoundActivity.java

 public void onClick(View v) {
                Intent intent = new Intent(SecoundActivity.this,ThirdActivity.class);
                startActivity(intent);
                EventBus.getDefault().postSticky("sticky0");
            }

@Subscribe(sticky = true,threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(String event) {
        Log.i("SecoundActivity", "MAIN_ORDERED : Subscribe Recv String Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

ThirdActivity.java

 @Subscribe(sticky = true,threadMode = ThreadMode.MAIN_ORDERED)
    public void onMainModeEvent(String event) {
        Log.i("ThirdActivity", "MAIN_ORDERED : Subscribe Recv String Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);

    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值