EventBus

EventBus

文章目录

  • EventBus
    • 1.EventBus的作用
    • 2.关于EventBus的概述
    • 3.EventBus的使用方法
    • 4.EventBus的黏性事件
    • 5.EventBus的源码
      • EventBus的构造方法
        • getDefault()源码
        • EventBus()源码
      • 订阅者注册
        • register()源码
        • findSubscriberMethods()源码
          • findUsingInfo()源码
          • findUsingReflectionInSingleClass()源码
          • findSubscriberMethods()流程图操作
        • subscribe()源码
      • 事件发送
        • postSingleEvent()源码
          • postSingleEventForEventType()源码
          • postToSubscription()源码
      • 订阅者取消注册

1.EventBus的作用

在没用EventBus的时候我们想想,我们是怎么样将第二个Activity的数据传递给第一个Activity的,还有怎么将第一个Activity的数据传递给第二个的,现在不回去看已经忘的差不多了。我们再想想ActivityActivity传数据还知道,那么FragmentFragment怎么传递数据。这就不知道了,为了解决这个问题,我们将使用组件化里面使用过的一个第三方库EventBus

EventBus简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。

2.关于EventBus的概述

1、三个角色
Event:事件,它可以是任意类型,EventBus会根据事件类型进行全局的通知。
Subscriber:事件订阅者,在EventBus
3.0之前我们必须定义以onEvent开头的那几个方法,分别是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件处理的方法名可以随意取,不过需要加上注解@subscribe,并且指定线程模型,默认是POSTING。
Publisher:事件的发布者,可以在任意线程里发布事件。一般情况下,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。
2.四种线程模型
EventBus3.0有四种线程模型,分别是:

POSTING (默认) 表示事件处理函数的线程跟发布事件的线程在同一个线程。
MAIN 表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。
BACKGROUND 表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程(UI线程),那么事件处理函数将会开启一个后台线程,如果果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。
ASYNC 表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。

3.EventBus的使用方法

首先先导入:

implementation("org.greenrobot:eventbus:3.3.1")

然后自定义一个事件类

public class EventBus {
    public EventBus(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    private String message;
}

第一个Activity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView tv_message;
    private Button bt_message;
    private Button bt_subscription;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_message = findViewById(R.id.tv_message);
        bt_message = findViewById(R.id.bt_message);
        bt_subscription = findViewById(R.id.bt_subscription);
        bt_subscription.setOnClickListener(this);
        bt_message.setOnClickListener(this);
        tv_message.setText("MainActivity");
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMoonEvent(EventBus eventBus){
        tv_message.setText(eventBus.getMessage());
    }

    @Override
    public void onClick(View view) {
        if(view.getId()==R.id.bt_message){
            startActivity(new Intent(MainActivity.this,SecondActivity.class));
        }
        else if(view.getId()==R.id.bt_subscription){
            if(!org.greenrobot.eventbus.EventBus.getDefault().isRegistered(this)) {
                org.greenrobot.eventbus.EventBus.getDefault().register(MainActivity.this);
            }
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        org.greenrobot.eventbus.EventBus.getDefault().unregister(this);

    }
}

其中

  if(!org.greenrobot.eventbus.EventBus.getDefault().isRegistered(this)) {
                org.greenrobot.eventbus.EventBus.getDefault().register(MainActivity.this);
            }

if语句是判断该订阅事件是否在这个Activity里面注册过,要是没有的话就执行

xxxx.getDefault().register();

进行订阅事件的注册

要是没有

 if(!org.greenrobot.eventbus.EventBus.getDefault().isRegistered(this))

你注册两次会报一个错误

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.eventbus_pratice, PID: 12132
org.greenrobot.eventbus.EventBusException: Subscriber class com.example.eventbus_pratice.MainActivity already registered to event class com.example.eventbus_pratice.EventBus
at org.greenrobot.eventbus.EventBus.subscribe(EventBus.java:168)
at org.greenrobot.eventbus.EventBus.register(EventBus.java:153)
at com.example.eventbus_pratice.MainActivity.onClick(MainActivity.java:42)
at android.view.View.performClick(View.java:7125)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1131)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access 3500 ( V i e w . j a v a : 801 ) a t a n d r o i d . v i e w . V i e w 3500(View.java:801) at android.view.View 3500(View.java:801)atandroid.view.ViewPerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

然后在onDestroy()里面注销

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


这段代码是事件订阅者处理事件

  @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMoonEvent(EventBus eventBus){
        tv_message.setText(eventBus.getMessage());
    }



第二个Activity

public class SecondActivity extends AppCompatActivity {
    private Button register;
    private Button bt_sticky;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        register = findViewById(R.id.register);
        bt_sticky = findViewById(R.id.bt_sticky);
        register.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                EventBus.getDefault().post(new com.example.eventbus_pratice.EventBus("事件发送成功!!!"));
                finish();
            }
        });
    }
}

下面这段代码是事件发布者发布事件

EventBus.getDefault().post(new com.example.eventbus_pratice.EventBus("事件发送成功!!!"));




在第一个ActivityTextViewMainActivity,先按注册那个按钮,再进入SecondActivity按下发送那个按钮你会发现MainActivityTextView变成了事件发送成功!!!

这就替代了之前第二个Activity给第一个Activity传递数据的方法

那么还有一个事情,如果我想先让第二个Activity给第一个Activity传递数据之后,我第一个Activity再按注册那个按钮可以吗,

答案是:这个代码是不行的,但是稍微改一改就可以了.

下面将讲到EventBus的黏性事件

4.EventBus的黏性事件

首先先改发送事件那块吧

SecondActivity中:

EventBus.getDefault().postSticky(new com.example.eventbus_pratice.EventBus("黏性事件发送成功!!!"));

之前我们的是:

xxx.post();

但是现在改成了:

xxx.postSticky();

然后是处理发送事件那块

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void ononMoonStickyEvent(EventBus eventBus){
    tv_message.setText(eventBus.getMessage());
}

原先反射那块是:

@Subscribe(threadMode = ThreadMode.MAIN)

现在要在后面多加一个

,sticky = true

现在我们就可以做到先发送事件,后注册了。

5.EventBus的源码

EventBus的构造方法

getDefault()源码

public static EventBus getDefault() {
    EventBus instance = defaultInstance;
    if (instance == null) {
        synchronized (EventBus.class) {
            instance = EventBus.defaultInstance;
            if (instance == null) {
                instance = EventBus.defaultInstance = new EventBus();
            }
        }
    }
    return instance;
}

用的DCL单例模式,确保缺省状态下EventBus的实例只有一个,现在

我们想要知道EventBus这个类下的instance是怎么创建的,就得点击**new EventBus()**查看它里面的源码了

EventBus()源码

public EventBus() {
    this(DEFAULT_BUILDER);
}

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;
}

这段代码的主要作用是初始化EventBus实例,并为其设置必要的参数和成员变量,以便后续在使用EventBus时能够正常工作。其中,包含了创建各种Poster、Finder和Executor的实例,并将它们赋值给相应的变量,这些实例在EventBus的后续使用中起到了关键作用。

订阅者注册

register()源码

public void register(Object subscriber) {
    if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) {
        // Crash if the user (developer) has not imported the Android compatibility library.
        throw new RuntimeException("It looks like you are using EventBus on Android, " +
                "make sure to add the \"eventbus\" Android library to your dependencies.");
    }

    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

首先

AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()

if语句的这段代码是用来检查当前是否在Android环境下,并且是否导入了EventBus库的Android兼容库。如果未导入,将会抛出异常。


  Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

首先是获得subscriber对象的Class对象,并使用subscriberMethodFinder对象查找该对象中所有的订阅者方法,返回一个SubscriberMethod列表。


 synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }

在同步块中,for循环遍历了subscriberMethods列表中的每一个SubscriberMethod对象,然后调用了subscribe方法将该SubscriberMethod对象中的订阅者方法添加到订阅列表中。并完成了订阅者的注册(订阅者的注册是通过调用subscribe方法实现的)

所以可以看出来register方法主要实现了2个作用:

  1. 查找订阅者的订阅方法
  2. 订阅者的注册

SubscriberMethod类中主要用来保存订阅方法的Method对象,线程模式,事件类型,优先级,是否为黏性事件

刚才我们说了findSubscriberMethods()是用来查找subscriberClass中所有的订阅者方法,现在我们看看里面的源码

findSubscriberMethods()源码

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    if (ignoreGeneratedIndex) {
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}

逐一解析:

 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);

这段代码主要是从从缓存中获取给定类的SubscriberMethod列表。

然后下面的if语句则是对获得的SubscriberMethod列表进行判断

  if (subscriberMethods != null) {
        return subscriberMethods;
    }

如果可以从缓存中找到SubscriberMethod列表,那就把这个列表返回,结束操作,如果没有,则进行下面的操作


先了解一下下面那个if语句中的ignoreGeneratedIndex的作用

点击ignoreGeneratedIndex会发现

private final boolean ignoreGeneratedIndex;

ignoreGeneratedIndex是一个 boolean类型的实例变量

虽然在代码中,ignoreGeneratedIndex被声明为private final boolean类型,但它并不是一个常量。

在Java中,final关键字有两种使用方式:一种是用于声明常量,即一旦初始化后就不能被重新赋值的变量;另一种是用于声明不可变的变量,即变量的值在初始化之后不能被修改。

在上述代码中,虽然ignoreGeneratedIndex被声明为final,但它的值可以在构造函数中或者通过setIgnoreGeneratedIndex方法进行修改,因此它不是一个常量。

相反,ignoreGeneratedIndex是一个实例变量,它的值在实例化对象之后可以被修改。final关键字的使用可以保证在实例化对象之后,ignoreGeneratedIndex的值不会被再次修改,即保证了它的不可变性,但是它不满足常量的定义,因为它的值可以在实例化之前被修改。

因此,虽然ignoreGeneratedIndex被声明为private final boolean类型,但它不是一个常量。

一般用ignoreGeneratedIndex属性的值选择用何种方法查找订阅方法的集合,表示是否忽略注释器生成的MyEventBusIndex

默认ignoreGeneratedIndex的值为false

如果ignoreGeneratedIndextrue执行

 subscriberMethods = findUsingReflection(subscriberClass);

用于通过反射机制查找给定类中带有@Subscribe注解的方法,并将它们封装成SubscriberMethod对象的列表。

如果为false则执行

 subscriberMethods = findUsingInfo(subscriberClass);

接下来看

 if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }

如果subscriberMethods为空则抛出一个注释

如果不为空则放入缓存供下次使用。


现在我们再看看当ignoreGeneratedIndex为false的时候**,findUsingInfo(subscriberClass)**干了些什么

findUsingInfo()源码
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
      	 findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();//用于将当前正在查找的类设置为其父类。
    }
    return getMethodsAndRelease(findState);
}

其中

  FindState findState = prepareFindState();

FindState来保存查找的状态

然后调用

 findState.initForSubscriber(subscriberClass);

来初始化查找的状态

然后如果当前保存的查找的类不为空的话就进入while循环

findState调用subscriberInfo的getSubscriberMethods()方法将值传递给SubscriberMethod

然后遍历SubscriberMethod数组,,对于每一个SubscriberMethod对象,执行以下操作:

  • 调用findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)方法,判断subscriberMethod是否符合添加的条件。checkAdd方法的作用是:如果findState.checkMethod是否为true,则检查方法签名是否匹配;否则,只检查事件类型是否匹配。
  • 如果checkAdd方法返回true,则将subscriberMethod添加到findState.subscriberMethods列表中。

如果findState.subscriberInfo(即:如果当前保存的查找的类为空)

则调用:

findUsingReflectionInSingleClass(findState);

用于在单个类中使用反射查找并添加SubscriberMethod对象。

查看一下它的源码

findUsingReflectionInSingleClass()源码
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        try {
            methods = findState.clazz.getMethods();
        } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
            String msg = "Could not inspect methods of " + findState.clazz.getName();
            if (ignoreGeneratedIndex) {
                msg += ". Please consider using EventBus annotation processor to avoid reflection.";
            } else {
                msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
            }
            throw new EventBusException(msg, error);
        }
        findState.skipSuperClasses = true;
    }
    for (Method method : methods) {
        int modifiers = method.getModifiers();
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 1) {
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
                    Class<?> eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            }
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}

这么长的代码我们只用关注一个:

 methods = findState.clazz.getDeclaredMethods();

通过反射,获取订阅者所有的方法,根据方法的类型,参数,注解找到订阅方法,并将订阅方法信息保存到findState中

findSubscriberMethods()流程图操作

EventBus_第1张图片

subscribe()源码

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);
        }
    }

    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);

    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            // Existing sticky events of all subclasses of eventType have to be considered.
            // Note: Iterating over all events may be inefficient with lots of sticky events,
            // thus data structure should be changed to allow a more efficient lookup
            // (e.g. an additional map storing sub classes of super classes: Class -> List).
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<Class<?>, Object> entry : entries) {
                Class<?> candidateEventType = entry.getKey();
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

首先

Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

会根据

subscriber(订阅者)subscriberMethod(订阅方法)创建一个Subscription(订阅对象)

然后在

 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);

根据eventType获得subscriptions集合


如果之前根据subscriptions为空

那个集合就重新创建,并根据eventType保存在subscriptionsByEventType(Map集合)

 if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    }

然后在

  int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

根据订阅方法的优先级。将新的订阅对象插入到订阅对象集合中去。


 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);

通过subscriber(订阅者)获取subscribedEvents(事件类型集合)

如果subscribedEvents为空则重新创建,再将subscriber, subscribedEvents传给typesBySubscriber

 if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }

 if (subscriberMethod.sticky) {
        if (eventInheritance) {
            // Existing sticky events of all subclasses of eventType have to be considered.
            // Note: Iterating over all events may be inefficient with lots of sticky events,
            // thus data structure should be changed to allow a more efficient lookup
            // (e.g. an additional map storing sub classes of super classes: Class -> List).
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<Class<?>, Object> entry : entries) {
                Class<?> candidateEventType = entry.getKey();
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }

如果是黏性事件,则从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者

具体来说,subscribe方法做了三件事情:

  1. 维护了当前EventBus中的subscriptionsByEventType表;(将Subscriptions根据eventType封装到subscriptionsByEventType中)
  2. 维护了当前EventBus中的 typesBySubscriber表;(将subscribedEvents根据subscriber封装到 typesBySubscriber)
  3. 处理了粘性事件;

第一个表是代表消息事件类型和Subscription关联的一个表,
第二个表是表示订阅者Subscriber和消息事件类型关联的两个表,这两个表可以在发布事件时可以快速地找到对应的订阅者并调用其处理方法。

事件发送

就只看post()了,postSticky()就不看了

public void post(Object event) {
    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 {
            //处理队列中所有事件
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

先创建一个PostingThreadState用来保存事件队列和线程状态信息,然后从该对象中取出事件队列,将事件插入该队列中。

后面进行处理

而处理主要是在**postSingleEvent()**执行的

现在看看**postSingleEvent()**的源码

postSingleEvent()源码

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    if (eventInheritance) {
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

eventInheritance为是否向上查找的父类,默认为true

可通过EventBusBuilder配置,为true时,通过lookupAllEventTypes找到所有的父类并存在集合中,然后用postSingleEventForEventType逐一处理

看看postSingleEventForEventType的源码

postSingleEventForEventType()源码
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted;
            try {
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}

subscriptions = subscriptionsByEventType.get(eventClass);

取出该事件对应的Subscriptions(订阅对象集合)然后遍历该集合.将event与subscription传递给postingState然后在postToSubscription()处理

看看这个方法的源码

postToSubscription()源码
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);
    }
}

它是先取出订阅方法的线程模式然后分别处理

订阅者取消注册

public synchronized void unregister(Object subscriber) {
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

先从typesBySubscriber Map集合中拿取subscribedTypes(事件类型集合)在不等于null情况下遍历将subscriber(订阅者)移除掉。

而它上面的代码

unsubscribeByEventType(subscriber, eventType);

用于取消订阅者订阅某个特定类型的事件

看看里面的源码

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) {
            Subscription subscription = subscriptions.get(i);
            if (subscription.subscriber == subscriber) {
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}

通过eventType得到对应的subscriptions并在for循环判断该订阅集合(subscriptions)对应的订阅对象(subscriber)的属性与传进来的是否相等,一样的话就移除。

你可能感兴趣的:(android,ui,java,android)