EventBus

(一)介绍

1,EvenetBus是一种发布-订阅事件总线.

代码简洁,开销小,并很好的实现了发送者和接收者的解耦.(是一种观察者模式)

2,三要素:
  • Event:事件

  • Publisher:发布者,可以在任意线程发布事件

  • Subscrible:订阅者,

3,通常情况下安卓下数据的传递有下面几种方法:
  • 3.1.通过intent传递,包括显式意图和隐式意图,广播(Broadcast)和服务都能通过Intent传递
    传递的数据类型包括8大基本数据类型 实现Parcelable或Serializable接口的类型 以及集合数组类型

  • 3.2.静态变量传递 在工具类下 声明一个Object类型的静态变量 在A中将要传递的值,在B中通过这个静态变量取出来

  • 3.3.通过handle在不同的线程中传递Object类型的数据

  • 3.4.通过构造方法传递Object类型的数据

  • 3.5.通过SharedPreferences传递八大基本数据类型

  • 3.6.通过ContentProvider在进程间共享数据

  • 3.7.通过aidl在进程进程传递数据

  • 3.8.通过流(本地文件)传递八大基本数据类型和实现Serializable接口的数据类型

  • 3.9.通过基类中的属性或者方法
    属性: 基类公有属性 在某个子类中赋值 其他子类中都能使用
    方法: 子类调用父类的某个方法给父类某个属性赋值 另外一个子类通过父类的另一个公有方法获取这个值(这个方法把值返回)

(二)基本使用

先订阅,后发布

1,添加依赖
compile 'org.greenrobot:eventbus:3.1.1'
2,注册事件
public class MessageEvent {

    private String message;

    public MessageEvent(String message){
        this.message = message;
    }

    public String getMessage(){
        return message;
    }
}
3,在接受消息的代码
      //注册成为订阅者
      EventBus.getDefault().register(this);

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解除注册
        EventBus.getDefault().unregister(this);
    }

    //订阅方法,当接收到事件的时候,会调用该方法
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(MessageEvent messageEvent){
        Log.e("date","receive it");
        Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
    }
4,在发送消息的地方
EventBus.getDefault().post(new MessageEvent("从fragment将数据传递到activity22222222"));

先发布,再订阅,黏性事件

5,在接受消息的代码
     //注册成为订阅者
      EventBus.getDefault().register(this);

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解除注册
        EventBus.getDefault().unregister(this);
    }

    //订阅方法,当接收到事件的时候,会调用该方法
    @Subscribe(threadMode = ThreadMode.MAIN,stick = true)
    public void onEvent(MessageEvent messageEvent){
        Log.e("date","receive it");
        Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
    }
6,在发送消息的地方
EventBus.getDefault().postSticky(new MessageEvent("从fragment将数据传递到activity22222222"));

(三)四个订阅方法

onEvent:

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

onEventMainThread:

如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。

onEventBackground:

如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。

onEventAsync:

使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync。

(四)源码解析

这里写图片描述
这里写图片描述
可以看到,发布者(Publisher)使用post()方法将Event发送到Event Bus,而后Event Bus自动将Event发送到多个订阅者(Subcriber)。这里需要注意两个地方:
(1)一个发布者可以对应多个订阅者。
(2)3.0以前订阅者的订阅方法为onEvent()、onEventMainThread()、onEventBackgroundThread()和onEventAsync()。在Event Bus3.0之后统一采用注解@Subscribe的形式,具体实现方式见下文。

   // 1主线程调用
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void eventBusMain(String str){
        Log.i("TAG", "MAIN:"+str+" Thread="+Thread.currentThread().getId());
    }

    // 2.发布线程为主线程,新开线程调用
    // 2.发布线程为子线程,发布线程调用
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void eventBusBg(String str){
        Log.i("TAG", "BACKGROUND:"+str+" Thread="+Thread.currentThread().getId());
    }

    //3,哪个线程发布,就在哪个线程调用
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void eventBusPosting(String str){
        Log.i("TAG", "POSTING:"+str+" Thread="+Thread.currentThread().getId());
    }

    // 4,每次都新开线程调用
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void eventBusAsync(String str){
        Log.i("TAG", "ASYNC:"+str+" Thread="+Thread.currentThread().getId());
    }
1,调用getDefault(),里面采用单利双重锁模式创建Eventbus对象
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}
2,构造方法
  • 2.1,粘性事件,保存到ConCurrenHashMap集合,(在构造方法中实现),
    HashMap效率高,但线程不安全,在多线程的情况下,尽量用ConcurrentHashMap,避免多线程并发异常
EventBus(EventBusBuilder builder) {
    logger = builder.getLogger();
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>(); //线程安全,
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}
3,注册register()方法主要做了2件事:
  • 3.1,找到订阅者的方法.找出传进来的订阅者的所有订阅方法,然后遍历订阅者的方法.
    A,通过反射来获取订阅者中所有的方法,并根据方法的类型,参数和注解找到订阅方法.
  • 3.2,订阅者的注册
public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    //找到订阅者的方法.找出传进来的订阅者的所有订阅方法,然后遍历订阅者的方法.
  List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            //订阅者的注册
             subscribe(subscriber, subscriberMethod);
        }
    }
}


private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // 通过反射来获取订阅者中所有的方法
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // 

,并根据方法的类型,参数和注解找到订阅方法.
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;}
//通过CopyOnWriteArrayList保存Subscription,
    //Arraylist效率高,但线程不安全,在多线程的情况下,使用CopyOnWriteArrayList,避免多线程并发异常

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }
4,事件发送post(),
public void post(Object event) {
  //PostingThreadState 保存着事件队列和线程状态信息
   PostingThreadState postingState = currentPostingThreadState.get();
    //获取事假队列,并将当期事件插入事件队列
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);

    if (!postingState.isPosting) {
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
         //处理队列中的所有事件,
        //将所有的事情交给postSingleEvent处理,并移除该事件
          while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}
5,取消事件订阅
public synchronized void unregister(Object subscriber) {
    //typesBySubscriber是一个map集合,
    //通过subscriber找到 subscribedTypes (事件类型集合),
     List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        //将subscriber对应的eventType从typesBySubscriber移除
    typesBySubscriber.remove(subscriber);
} else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); }}

借鉴:刘望舒先生的进阶之光

Android EventBus3.1.1从使用到源码解析
Android EventBus 使用详解
EventBus的使用,数据传递
EventBus 3.0进阶:源码及其设计模式 完全解析

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值