Android EventBus使用理解

EventBus优点

  1、简化组件间的交互
    解耦事件发送者和接收者
    与Activities, Fragments, 和 后台线程之间使用 表现的好
    避免复杂和易错的库和生命周期问题
  2、让你的代码更简洁
  3、是快速的
  4、文件极小(jar包大概60k)
  5、有先进的特色像传递线程、订阅者优先级等
  6、在实际使用中APP安装超过10亿次
  这些特点是它们官方写的,我们现在使用一个例子来看一下,它的使用。

使用例子

  这里使用一个Activity和一个Fragment来举例子,简单看一下,EventBus是怎么使用的。
  下面是MainActivity的代码:

public class MainActivity extends FragmentActivity {
    
    
    public static final String TAG = "MainActivity";
    private TextView main_tv;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_ac);
        main_tv = findViewById(R.id.main_tv);
        FragmentManager fmanager = getSupportFragmentManager();
        FragmentTransaction trac = fmanager.beginTransaction();
        trac.add(R.id.main_fl, new BusFragment());
        trac.commit();
        EventBus.getDefault().register(this);
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent met) {
    
    
        main_tv.setText(met.toString());
        Log.e(TAG, "onMessageEvent接收到消息:" + met);
    }

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

  里面主要是有个文本控件TextView main_tv,添加了一个BusFragment。
  它在onCreate()中执行了注册订阅者,这里的订阅者就是MainActivity 。在onDestroy()中执行取消注册。
  同时它还使用@Subscribe注解,来声明接收方法和事件。
  事件是用类来定义的,这里就是MessageEvent

public class MessageEvent {
    
    
    int count;
    String con;
    @Override
    public String toString() {
    
    
        return "MessageEvent{" +
                "count=" + count +
                ", con='" + con + '\'' +
                '}';
    }
}

  事件类里有两个变量count和con。
  再看看BusFragment里面的代码:

public class BusFragment extends Fragment {
    
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
    
    
        View view = inflater.inflate(R.layout.bus_frag, container, false);
        Button frag_btn = view.findViewById(R.id.frag_btn);
        frag_btn.setOnClickListener(itview ->{
    
    
            MessageEvent et = new MessageEvent();
            et.count = 10;
            et.con = "测试内容";
            EventBus.getDefault().post(et);
        });
        return view;
    }
}

  BusFragment里面有个按钮frag_btn ,点击之后,会将事件类赋值,然后调用EventBus.getDefault().post(et)发布事件。
  这样就能向MainActivity中发布事件,MainActivity就能在它的onMessageEvent()中接到事件消息了。
  这样就能实现Activity与Fragment交互了。通过代码来看,是比较简洁。

源代码分析

  下面就从注册订阅者,发布事件,取消注册订阅者三个方面来分析。

注册订阅者

  调用的是EventBus.getDefault().register(this),在这里this是MainActivity,它是订阅者。
  先是调用EventBus.getDefault()生成一个默认EventBus对象,然后才是调用注册订阅者register(this)。

生成一个默认EventBus对象

  EventBus的成员变量,拣几个重要的说一下,如下:
EventBus成员变量

EventBus成员变量
  subscriptionsByEventType:它是一个容器,它的key是事件类的Class,值是Subscription的集合。Subscription类则是订阅者和订阅方法相关信息的描述。Subscription有两个成员变量Object subscriber和SubscriberMethod subscriberMethod。其中subscriber是订阅者,subscriberMethod则是订阅方法的信息。   typesBySubscriber:key是订阅者,值为订阅者订阅的事件类Class。

  stickyEvents:则为粘性事件相关的,key为粘性事件类的Class,值则为粘性事件类对象。
  mainThreadSupport:用来判断当前执行的线程是不是在主线程中
  mainThreadPoster:主要用来处理threadMode为MAIN或MAIN_ORDERED的订阅方法的执行,将它们放到主线程中去执行。
  backgroundPoster:主要用来处理threadMode为BACKGROUND的订阅方法的执行,要执行订阅方法的时候,如果发现是在主线程,backgroundPoster会将订阅方法是现在后台线程中执行。
  asyncPoster:主要用来处理threadMode为ASYNC的订阅方法的执行,这里主要强调的是异步,就是在要执行订阅方法的时候,是要启动新线程去执行该方法。
  subscriberMethodFinder:顾名思义,订阅方法的查找者。没错就是在该类中找到的订阅方法。后面详细说明。
  executorService:线程池,它默认为Executors.newCachedThreadPool()。
  throwSubscriberException:默认为false。如果执行订阅方法时,出现异常,是否会抛出异常。
  sendSubscriberExceptionEvent:默认为true。如果执行订阅方法时,出现异常,是否发送SubscriberExceptionEvent事件。
  sendNoSubscriberEvent:默认为true。在发布事件时,如果没找到对应的订阅方法执行,是否会发布NoSubscriberEvent事件。
  eventInheritance:在发布事件的时候,不止会发布它本身类型,还会发布它继承的所有接口、类 事件类型。默认为true;如果在订阅粘性事件时,却是会找到它本身和它的子类的事件,进行发布。
  EventBus的构造使用的是建造者模式,使用的是EventBusBuilder。看一下EventBus.getDefault():

    static volatile EventBus defaultInstance;
    …………
    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;
    }

  典型的单例生成双检查,因为最开始defaultInstance为null,所以会走到EventBus的初始化函数

    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();   
    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;
    }

  DEFAULT_BUILDER 是EventBus类的静态变量,我们看到,这里没有使用构造着经典的build()方法,而是采用的赋值方式来生成EventBus对象。其中各个变量,在上面介绍类对象成员变量时,都说了。

注册订阅者

  看一下EventBus的register(Object subscriber)方法:

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

  参数subscriber是订阅者,在上面的例子里,是MainActivity实例。
  先得到subscriber的Class,然后调用EventBus的成员变量subscriberMethodFinder的findSubscriberMethods(),得到对应Class上面的订阅方法(@Subscribe标注的方法)。
  再循环调用subscribe(subscriber, subscriberMethod)方法将subscriber订阅subscriberMethod。实际就是将subscriber和subscriberMethod放到相应数据结构(主要是subscriptionsByEventType和typesBySubscriber)中,等待订阅事件发布时,去相关数据结构中拿到相关信息执行订阅方法。

得到订阅者实现的订阅方法

  它主要是调用subscriberMethodFinder.findSubscriberMethods(subscriberClass)得到。subscriberMethodFinder是SubscriberMethodFinder类对象,参数subscriberClass是上面得到的订阅者的Class。它的代码执行方法如下:
findSubscriberMethods执行流

findSubscriberMethods()代码执行流

  现在看一下具体的SubscriberMethodFinder类的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;
        }
    }

  参数subscriberClass是订阅者对象的Class,订阅者对象上允许生命多个订阅方法,所以查找出来的结果是集合List。METHOD_CACHE是ConcurrentHashMap<Class<?>, List>对象,它是用作缓存使用的,如果之前查找过,就将结果存储起来,key值就是订阅者对象的Class。所以如果从缓存中查询出来之后,就拿到对应的结果不为null,就直接返回了。
  ignoreGeneratedIndex默认为false,所以调用findUsingInfo(subscriberClass)得到结果。
  最后会将结果放入METHOD_CACHE中。
  我们再看findUsingInfo(subscriberClass)之前,需要先了解一下FindState 类结构如下:
FindState类结构图

FindState类结构图
  subscriberMethods:就是查找出来的所有订阅方法。

  anyMethodByEventType:是用来在查找过程中做判断用的,key是事件类型的Class,value则是Method或者FindState类对象。
  subscriberClassByMethodKey也是用来在查找过程中做判断用的,key是方法名称 + “>” + 事件类型名,value是方法的生命类的Class(订阅类的Class)。
  methodKeyBuilder:是用来拼subscriberClassByMethodKey的key值
  subscriberClass:订阅者类的Class
  clazz:刚开始订阅者类的Class,后面会向它的父类Class递归
  skipSuperClasses:是否跳过父类的Class里面方法的查找
  subscriberInfo:订阅者信息,目前一直为null
  FindState类还使用缓存机制。它的实现是SubscriberMethodFinder的FIND_STATE_POOL。它是一个FindState数组,大小为4。
  现在可以继续看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);
    }

  prepareFindState()方法就是先取FIND_STATE_POOL中的对象,如果没有,会重新生成一个。
  findState.initForSubscriber(subscriberClass)就是将findState的subscriberClass和clazz设置为订阅者的Class。skipSuperClasses为false,subscriberInfo为null。
  下面会进入一个while循环,因为findState.subscriberInfo为null,所以对当前findState.clazz不为null进行处理findUsingReflectionInSingleClass()完之后,会向它的父类Class遍历,继续执行。转向父类Class是通过findState.moveToSuperclass()实现的。
  最后会调用getMethodsAndRelease(findState)得到findState对象成员subscriberMethods里面存储的结果,并且将findState放入缓存池FIND_STATE_POOL中。
  这里最主要的处理还是findUsingReflectionInSingleClass(findState)。看完它,我们就能知道EventBus是怎么通过反射来实现的查找订阅方法了。

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

  目前findState.clazz是订阅者的Class,也就对应着上述例子中的MainActivity的Class。通过反射机制,调用它的getDeclaredMethods()方法,得到自己类声明的所有方法。如果该方法发生异常,会调用getMethods(),注意getMethods()会返回包含的从超类和超接口继承的public方法,并且会将skipSuperClasses设置为true。因为已经得到了所有的方法,不用再向父类遍历。
  接着对查询到的Method,进行循环。
  首先判断方法的修饰符,可见订阅方法需要设置成public。并且不能带一下四种修饰符,Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC。Modifier.ABSTRACT | Modifier.STATIC这俩我们知道,抽象方法或静态方法。BRIDGE | SYNTHETIC则是在以具体类型继承自一个泛型类,同时被继承的泛型类包含了泛型方法,则该方法会带BRIDGE | SYNTHETIC标识。在这里我们需要知道这种类上的对应方法声明订阅方法不起作用。
  订阅方法的参数只能为一个,并且需要有Subscribe注解。strictMethodVerification默认为false,如果设置为true,则会报异常EventBusException。
  eventType是方法参数的Class,也就是订阅事件类的Class。会通过findState.checkAdd(method, eventType)来判断是否能将方法和相关信息添加到findState.subscriberMethods中。SubscriberMethod类就是来描述订阅方法的。它的成员包括执行方法Method,事件类型还有通过注解Subscribe得到的threadMode,priority、sticky。
  下面看一下findState.checkAdd(method, eventType),看一下什么情况下,能添加方法。

        boolean checkAdd(Method method, Class<?> eventType) {
    
    
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type.
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {
    
    
                return true;
            } else {
    
    
                if (existing instanceof Method) {
    
    
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
    
    
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }

  可以看到每次添加新事件类型的时候,肯定是可以添加进去的。因为anyMethodByEventType里面对应的key对应的值为null。
  如果第二次添加同类型的事件呢?分两种情况,就是Method方法名称是否和之前添加的相同。还发现,第二次添加同种事件类型时,会执行两遍checkAddWithMethodSignature()方法。分两种情况讨论一下
  1、方法名和之前不同
  会通过anyMethodByEventType.put(eventType, method)得到之前添加的Method,因为它为Method,所以会进入第一次checkAddWithMethodSignature()方法判断。

        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
    
    
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());

            String methodKey = methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass();
            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
    
    
                // Only add if not already found in a sub class
                return true;
            } else {
    
    
                // Revert the put, old class is further down the class hierarchy
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }

  看到了吧,会拼凑key值为fangfaming + “>” + 事件类名作为key值。拿到声明方法的Class,添加到subscriberClassByMethodKey中,第一次添加这个key值,所以得到的methodClassOld为null,直接返回true。这里要想清楚的一点时,method是第一次添加事件时候的那个方法。
checkAddWithMethodSignature()第一遍执行返回true,之后,会将anyMethodByEventType里的值更新为FindState类对象。接着会走第二遍。这次method为要添加的方法,再次走到checkAddWithMethodSignature()方法里面,因为方法名字不同,所以生成key值,在subscriberClassByMethodKey还是没有对应的值,添加之后,methodClassOld 仍然为null,所以返回true。
  这个时候,是可以将订阅方法添加到结果中。
  2、方法名和之前相同
  这次和第一种情况不同的是在第二遍执行checkAddWithMethodSignature()的时候,第一遍执行的情况是一样的。
  第二遍checkAddWithMethodSignature生成key的值,由于方法名和事件名都一样,所以subscriberClassByMethodKey.put()的时候,返回的结果不为null了。它是第一次添加方法时方法的声明类。然后做methodClassOld.isAssignableFrom(methodClass)判断,methodClassOld为第一次添加方法时方法的声明类。methodClass为第二次添加方法的声明类。
  methodClassOld.isAssignableFrom(methodClass),是做判断methodClassOld是methodClass的父类、接口类或者相等的时候,会返回true。也就是第一次添加这种事件类型的类是第二种添加类型的类的父类、接口类或者相等的时候,会返回true。
  我们再思考一下,什么情况下,会添加方法名和事件类型都相同的订阅方法。同一个类中肯定不行,那只有在子类和父类中都定义了相同事件的方法名也一样的函数。通过findUsingInfo(),我们知道,是先从子类添加事件的,所以第一次添加这种事件类型的类是第二种添加类型的类的子类,遍历到父类添加方法时,肯定通过不了。所以我们知道FindState类的成员subscriberClassByMethodKey主要就是为了防止这种情况的。

  这样回到register(Object subscriber)方法里subscriberMethodFinder.findSubscriberMethods(subscriberClass)执行完毕,查找的结果都在subscriberMethods中了。

订阅者订阅方法

  看一下对应的subscribe()方法代码,代码有点长,分段来看:

    // Must be called in synchronized block
    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;
            }
        }


  它主要将订阅者,订阅对象封装到Subscription中,然后将它放入subscriptionsByEventType中。
  先生成Subscription对象newSubscription,它包含订阅者subscriber和订阅方法subscriberMethod。subscriptionsByEventType是以订阅事件的类型为key,如果为空,会新建一个并且,将新建的放进subscriptionsByEventType中。
  接着会根据优先级的大小来找位置。优先级越大,位置越靠前。
  再看一下subscribe()方法的第二段代码:

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

  这段代码挺简单,将订阅者订阅的事件类型放入typesBySubscriber中。
  再来看subscribe()方法的最后一段代码

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

  如果当前订阅方法是sticky,则会检查stickyEvents中的事件,如果他们是当前订阅方法事件类型的子类或同类,则会发布其中的事件。这就会实现,粘性事件发布之后,然后再订阅也是可以收到对应事件的。
  前面解释过eventInheritance,也解释过isAssignableFrom()方法。这里就是遍历stickyEvents里的事件,如果事件类型和当前绑定的eventType相同,或者是它的子类,就会调用checkPostStickyEventToSubscription(newSubscription, stickyEvent),执行发布。看一下它:

    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
    
    
        if (stickyEvent != null) {
    
    
            // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
            // --> Strange corner case, which we don't take care of here.
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

  粘性事件不为null,就去执行postToSubscription(newSubscription, stickyEvent, isMainThread()),执行发布,发布的内容在下面讲。

发布事件

  发布事件是调用的EventBus.getDefault().post(Object event):

    /** Posts the given event to the event bus. */
    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;
            }
        }
    }

  currentPostingThreadState是和线程相关的,调用get()会得到一个PostingThreadState类。它的成员eventQueue是ArrayList类型,用作事件队列。这里将事件放到队列中。
  postingState.isPosting代表是否正在发送事件。postingState.isPosting为false,下面就开始发送消息,然后接着就将postingState.isPosting为true。postingState.isMainThread被赋值为isMainThread(),代表当前线程是不是主线程。
  接着开启循环调用postSingleEvent(),将队列里里的事件发送。最后再将postingState.isPosting = false,postingState.isMainThread = false。

是否在主线程中

  看一下isMainThread(),看它是怎么确定主线程的

    private boolean isMainThread() {
    
    
        return mainThreadSupport == null || mainThreadSupport.isMainThread();
    }

  如果mainThreadSupport 为null或者mainThreadSupport.isMainThread()。这里mainThreadSupport是在EventBusBuilder中定义的,看一下

    MainThreadSupport getMainThreadSupport() {
    
    
        if (mainThreadSupport != null) {
    
    
            return mainThreadSupport;
        } else if (AndroidComponents.areAvailable()) {
    
    
            return AndroidComponents.get().defaultMainThreadSupport;
        } else {
    
    
            return null;
        }
    }

  可以看到主要是通过AndroidComponents.get().defaultMainThreadSupport得到的,AndroidComponents.get()为:

    private static final AndroidComponents implementation;

    static {
    
    
        implementation = AndroidDependenciesDetector.isAndroidSDKAvailable()
            ? AndroidDependenciesDetector.instantiateAndroidComponents()
            : null;
    }

    public static boolean areAvailable() {
    
    
        return implementation != null;
    }

    public static AndroidComponents get() {
    
    
        return implementation;
    }
    public final Logger logger;
    public final MainThreadSupport defaultMainThreadSupport;

    public AndroidComponents(Logger logger, MainThreadSupport defaultMainThreadSupport) {
    
    
        this.logger = logger;
        this.defaultMainThreadSupport = defaultMainThreadSupport;
    }    

  可以看到implementation是由AndroidDependenciesDetector.instantiateAndroidComponents()得到:

    private static final String ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME = "org.greenrobot.eventbus.android.AndroidComponentsImpl";    
    public static AndroidComponents instantiateAndroidComponents() {
    
    

        try {
    
    
            Class<?> impl = Class.forName(ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME);
            return (AndroidComponents) impl.getConstructor().newInstance();
        }
        catch (Throwable ex) {
    
    
            return null;
        }
    }

  可见,真正初始化的是AndroidComponentsImpl类

public class AndroidComponentsImpl extends AndroidComponents {
    
    

    public AndroidComponentsImpl() {
    
    
        super(new AndroidLogger("EventBus"), new DefaultAndroidMainThreadSupport());
    }
}

  可以看到它的defaultMainThreadSupport 为DefaultAndroidMainThreadSupport类对象。
  所以EventBus对象的mainThreadSupport为DefaultAndroidMainThreadSupport类对象
  看一下它的isMainThread()

    @Override
    public boolean isMainThread() {
    
    
        return Looper.getMainLooper() == Looper.myLooper();
    }

  判断当前线程的Looper是否等于主线程的Looper.getMainLooper(),如果相等,就是在主线程中,如果不等,就不再主线程。

发布单个事件

  看一下postSingleEvent(Object event, PostingThreadState postingState)的相关代码:

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

  eventClass 事件的类型Class,subscriptionFound 代表是否发布了事件。在这里可以看到eventInheritance的作用,是调用了lookupAllEventTypes(eventClass)找到了它的本身类的Class,还有它继承的父类和接口的相关Class。只要找到这些匹配的事件对象都会调用。
  接着对所有找到的事件类型,都调用postSingleEventForEventType(event, postingState, clazz)进行执行。看一下它的代码:

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

  它从subscriptionsByEventType里面得到需要执行的订阅方法的信息。如果找到了,遍历subscriptions,拿到subscription,继续调用postToSubscription(subscription, event, postingState.isMainThread)执行发送消息。

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

  这里就开始处理订阅方法。在处理之前,还需要看看是否要产生线程调度。例如,这里配置的threadMode为MAIN,就是要求需要在主线程中执行,前面我们已经判断调用的线程是否在主线程中,现在由变量isMainThread控制。如果isMainThread为true,直接就调用invokeSubscriber(subscription, event),如果isMainThread为false,则调用mainThreadPoster.enqueue(subscription, event)。

线程调度

咱们就选择配置为主线程的调用的来讲讲它是怎么实现执行调度的。
  首先,如果目前就在主线程中,不产生线程调度,直接执行invokeSubscriber(subscription, event):

    void invokeSubscriber(Subscription subscription, Object event) {
    
    
        try {
    
    
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
    
    
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
    
    
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

  直接就调用Method的invoke方法实现方法执行。subscription.subscriber就是订阅者对象,event就是事件,subscription.subscriberMethod.method就是订阅方法。
  再看看目前不在主线程中,调用mainThreadPoster.enqueue(subscription, event)。mainThreadPoster是mainThreadSupport.createPoster(this)生成的,前面我们知道mainThreadSupport是DefaultAndroidMainThreadSupport类对象。看一下DefaultAndroidMainThreadSupportd的createPoster(this)

    @Override
    public Poster createPoster(EventBus eventBus) {
    
    
        return new HandlerPoster(eventBus, Looper.getMainLooper(), 10);
    }

  所以mainThreadPoster是HandlerPoster对象。看一下HandlerPoster的enqueue(subscription, event)

    public void enqueue(Subscription subscription, Object event) {
    
    
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
    
    
            queue.enqueue(pendingPost);
            if (!handlerActive) {
    
    
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
    
    
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

  HandlerPoster是继承了Handler类的,它在将调用信息和事件封装成一个PendingPost 对象之后,放到queue里。然后它在这里调用sendMessage(obtainMessage())发送消息,通过Android的消息传递机制,实现线程调度。
再看看HandlerPoster的handleMessage(Message msg):

    @Override
    public void handleMessage(Message msg) {
    
    
        boolean rescheduled = false;
        try {
    
    
            long started = SystemClock.uptimeMillis();
            while (true) {
    
    
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
    
    
                    synchronized (this) {
    
    
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
    
    
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
    
    
                    if (!sendMessage(obtainMessage())) {
    
    
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
    
    
            handlerActive = rescheduled;
        }
    }
}

  可以看到,从队列里面拿到PendingPost对象,接着调用eventBus.invokeSubscriber(pendingPost)去执行。

    void invokeSubscriber(PendingPost pendingPost) {
    
    
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
    
    
            invokeSubscriber(subscription, event);
        }
    }

    void invokeSubscriber(Subscription subscription, Object event) {
    
    
        try {
    
    
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
    
    
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
    
    
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

  判断一下Subscription 对象的active为true,代表它是活跃状态,然后才去执行它的订阅方法。最终也是执行了Method的invoke(),执行了订阅方法的调用。
  其他线程模式的切换,都是调用了EventBus对象的线程池实现的,这里不细说了。

取消注册订阅者

  取消订阅者,就是你不想要订阅这个事件了,这个时候,需要执行EventBus.getDefault().unregister(this)方法。看下它的代码:

    /** Unregisters the given subscriber from all event classes. */
    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());
        }
    }

    /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    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--;
                }
            }
        }
    }

  主要是处理typesBySubscriber和subscriptionsByEventType。
  通过typesBySubscriber得到订阅者都订阅了哪些类型的事件,然后遍历所有事件类型,再调用unsubscribeByEventType(subscriber, eventType)去处理subscriptionsByEventType里的订阅事件信息。遍历完成后,typesBySubscriber会将该订阅者去除。
  unsubscribeByEventType(subscriber, eventType)也是找到里面符合取消订阅者的订阅信息类Subscription 。将它subscription.active = false,删除掉。

总结

  分析完整个框架代码,我们知道EventBus是通过反射来实现订阅方法的注册、订阅方法的执行。通过注解能设置订阅方法的线程调度、优先级、粘性事件。确实使用起来比较简单,代码看起来也比较简洁。它在自己内部实现了线程调度,用户只需设置订阅方法的线程调度模式即可。

思考

  思考:反射机制是会影响程序的性能的,如果订阅者对象类是一个方法很多的类,包括它的父类的方法很多,应该都会产生影响。像前面的那个例子,MainActivity是继承的FragmentActivity,FragmentActivity又继承了其他类,难道这些都需要遍历吗?
  我们把查找订阅对象的方法再拿出来看一下:

    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.clazz为null的时候,会停止。查询完当前MainActivity的Class之后,会走findState.moveToSuperclass(),看一下,它怎么找父类的:

        void moveToSuperclass() {
    
    
            if (skipSuperClasses) {
    
    
                clazz = null;
            } else {
    
    
                clazz = clazz.getSuperclass();
                String clazzName = clazz.getName();
                // Skip system classes, this degrades performance.
                // Also we might avoid some ClassNotFoundException (see FAQ for background).
                if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
                        clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) {
    
    
                    clazz = null;
                }
            }
        }

  看到了吧,如果父类是以"java."“javax.”、“android.”、"androidx."开头的包名,那就认为找到了系统提供的类了。我们一般也不会自己定义该种包开头的类,像例子中的父类FragmentActivity,完整带报名androidx.fragment.app.FragmentActivity,所以,就会将clazz设置为null。直接就跳出循环了。
  行了,该篇文章到这结束了。

猜你喜欢

转载自blog.csdn.net/q1165328963/article/details/132199687