事件总线——EventBus 源码分析及手写一个Evenbus

跟随大神Darren (源代码的来源者是Darren)的学习历程:

第一部分:源码分析

1.现象描述:

  1.1 在MainActivity(需要订阅事件的地方)的onCreat()中注册EventBus

 EventBus.getDefault().register(this);

  1.2 在MainActivity(需要订阅事件的地方)的onDestory()注销EventBus

EventBus.getDefault().unregister(this);
super.onDestroy();

   1.3 在MainActivity中处理事件

/**
     * threadMode 执行的线程方式
     * priority 执行的优先级,值越大优先级越高
     * sticky 粘性事件
     */
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 100,sticky = true)
    public void test2(String msg){
        // 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
        Log.e("TAG","msg2 = "+msg);
        mTv.setText(msg);
    }

   1.4 在任意地点只要调用 EventBus.getDefault().post() 方法就会只是Subscribe的注解方法,前提是同类性的对象

   

事件总线解决的问题:

  1. 优点:它简化了应用程序内各组件间,组件和后台线程间的通信。

EventBus的参数详考:

三要素:

              1.Event:事件。可以是任意类型的对象

              2.Subscriber:事件订阅者。EventBus3.0之前消息处理的方法只能限定onEvent,onEventMainThread,onEventBackgroundThread,  和onEventAsync,它们分别代表四种不同的线程模型。EventBus3.0之后,事件处理的方法可以随便取名,但是需要添加一个直接@Subscriber,并且要指定线程模型(ThreadMode,默认为POSTING)。

              3.publisher:事件发布者。可以在任意线程任意位置发送事件,直接调用EventBus的post(Object)方法。可以自己实例化EventBus对象,但一般使用EventBus.getDefault()就可以,根据post()函数参数的类型,会自动调用订阅者的相应订阅事件。

 四种模式(ThreadMode):

              1.POSTING(默认):该事件在哪个线程发不出来的,事件处理函数就会在哪个线程中运行,也就是说发布事件和接收事件在同一个线程中。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为他堵塞事件的传递,甚至由可能会引起ANR。(比如Second在主线程发的事件,Main也会在主线程处理,如果在子线程发的,Main就会在子线程去处理了。所以存在一定的危险性。)

扫描二维码关注公众号,回复: 4986268 查看本文章

              2.MAIN:事件的处理会在UI线程中执行。事件处理的时间不能太长,太长会导致ANR。(这个会了,其他还不太明确)

              3.BACKGROUND:如果事件事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行。如果事件本来就是在子线程中发不出来的,那么该事件处理函数直接在发布事件的线程中执行,在次事件处理中禁止进行UI更新操作。

              4.ASYNC:无论事件在哪个线程中发布,该事件处理函数都会在新建的子线程中执行;同样,此事件处理函数中禁止进行UI更新操作。

2.EventBus应用举例:

第一步:添加依赖 https://github.com/greenrobot/EventBus

第二步:定义消息事件类: 

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

    public String getMessage(){

        return message;
    }

    public void setMessage(String message){

        this.message = message;
    }
}

第三步:注册和取消EventBus,并实现订阅事件:

public class MainActivity extends AppCompatActivity{

    private TextView tv_message;
    private Button bt_message;
    private Button bt_suscription;

    @Override
    protected void onCreat(Bundle saveInstanceState){
        super.onCreat(saveInstanceState);
        setContentView(R.layout.activity_main);
        
        tv_message = fb();
        tv_message.setText("MainActivity");
        bt_suscription = fb();
        bt_suscription.setText("注册EventBus");
        bt_message = fb();
        bt_message.setText("跳转到SecondActivity");
        
        bt_message.setOnClickListener(new View.onClickListener(){

           @Override
            onClick(View v){

                 startActiviy(this,new Intent(MainActivity.this,              
                                                   SecondActivity.class));
            }
        });

         bt_suscription.setOnClickListener(new View.onClickListener(){

           @Override
            onClick(View v){

                 //注册 EventBus
                 EventBus.getDefault().register(MainActivity.this);
            }
        });
    }

      /**
     * threadMode 执行的线程方式
     * priority 执行的优先级,值越大优先级越高
     * sticky 粘性事件
     */
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 100,sticky = true)
    public void test1(String msg){
        // 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
        Log.e("TAG","msg2 = "+msg);
        m_message.setText(msg);
    }

    //非粘性
   @Subscribe(threadMode = ThreadMode.MAIN,priority = 50)
    public void test1(String msg){
        // 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
        Log.e("TAG","msg2 = "+msg);
        m_message.setText(msg);
    }

      @Override
        onDestory(){
           //注销EventBus
           EventBus.getDefault().unregister(this);
           super.onDestory();
        }
}

第四步:在SecondActivity中发送消息:

public class SecondActivity{

    private Button bt_message1;
    private Button bt_message2;
    private TextView tv_message;
    
    @Override
    protected void onCreate(Bundle saveInstanceState){
        super.onCreate(saveInstance);
        setContentView(R.layout.activity_second);

        bt_message1 = fb();
        bt_message2 = fb();
        tv_message = fb();
        tv_message.setText("SecondActivity");
        bt_message1.setText("发送非粘性实现事件");
        bt_message2.setText("发送粘性实现事件");
  
        bt_message1.setOnClickListener(new onClickListener(){

          @Override
          public void onClick(View v){
            
               //形式一:
               EventBus().getDefault().post(new MessageEvent("main, second(非粘性) 叫你起床
          了。")); 
               //形式了
               EventBus eb = new EventBus();
                 sb..post(new MessageEvent("main, second 叫你起床
          了。")); 
          }
        });

        bt_message2.setOnClickListener(new onClickListener(){

          @Override
          public void onClick(View v){
            
               //形式一:
               EventBus().getDefault().postSticky(new MessageEvent("main, second 叫你起床
          了。")); 
               //形式了
               EventBus eb = new EventBus();
                 sb.postSticky(new MessageEvent("main, second(粘性) 叫你起床
          了。")); 
          }
        });            
    }
}

非黏性事件和黏性事件的区别:

非黏性: Main 注册前,Second发的事件Main收不到。

黏性:Main注册前,Second发的事件Main收得到。

源码分析:

1.getDefault();  //单例

/** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

2.EventBus注册的源码分析 register(activity);

public void register(Object subscriber) {
        // 首先获得class对象
        Class<?> subscriberClass = subscriber.getClass();
        
        //遍历这个Class的所有方法,找到有Subscrible注解的所有方法,生成一个List集合,然后返回。
        
List<SubscriberMethod> subscriberMethods =                      subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        
         synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                // 订阅
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

2.1 遍历这个Class的所有方法,找到有Subscrible注解的所有方法,生成一个List集合,然后返回。

 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 先从缓存里面读取,订阅者的 Class
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        //支持编译时注解的方式,引入eventbus的apt
        // ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex。
        // ignoreGeneratedIndex的默认值为false,可以通过EventBusBuilder来设置它的值
        if (ignoreGeneratedIndex) {  //默认为false (getDefault())
            // 利用反射来获取订阅类中所有订阅方法信息
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            // 从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法信息
            // 这个这里不说,可以去看看之前的编译时注解
            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;
        }
    }

2.2,findUsingInfo(MainActivity);

 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        // FindState 涉及到 享元设计模式
        FindState findState = prepareFindState();

        findState.initForSubscriber(subscriberClass);
        //
        while (findState.clazz != null) {  //findState.clazz != null一定不是null
            //在不使用apt的情况下,返回null
            findState.subscriberInfo = getSubscriberInfo(findState);
                   
            if (findState.subscriberInfo != null) { //不用apt的情况下此路不通
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else { //不用apt的情况下,会走这条路。
                //通过反射去找。
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        // 释放 findState 享元模式
        return getMethodsAndRelease(findState);
    }

2.3getSubscriberInfo(findState) 使用apt走这个方法,再走findState.subscriberMethods.add(subscriberMethod);

//默认情况下返回null,用了编译时注解,才不是空。
private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        if (subscriberInfoIndexes != null) {
            //subscriberInfoIndexes默认为null
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

2.4 不使用apt走这个方法。

   2.4.1findUsingReflectionInSingleClass()

      这个方法去解析注册者对象的所有方法,并且找出带有注解Subscriber注解的方法,

     然后通过Annotation解析所有的细节参数(threadMode,priority,sticky,eventType,method),把这些参数封装成一个SubscriberMethod,添加到集合返回。

//这个方法,实在不使用apt的情况下,注册时查找方法的核心代码。 
private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            // 通过反射来获取订阅类的所有方法 findState.clazz——MainActivity
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        // for 循环所有方法
        for (Method method : methods) {
            // 获取方法访问修饰符
            int modifiers = method.getModifiers();
            //  找到所有声明为 public 的方法
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();// 获取参数的的 Class
                if (parameterTypes.length == 1) {// 只允许包含一个参数
          
          //获取有Subscribe注解的方法。
          Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); 
                    if (subscribeAnnotation != null) {
                        // 获取事件的 Class ,也就是方法参数的 Class
                        Class<?> eventType = parameterTypes[0];
                        // 检测添加
                        if (findState.checkAdd(method, eventType)) {
                            // 获取 ThreadMode
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 往集合里面添加 SubscriberMethod ,解析方法注解所有的属性
                            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");
            }
        }
    }

2.5  subscribe();  遍历集合调用该方法,对订阅方法进行处理。

解析所有的SubscriberMethod的eventType,然后按照一定的要求解析成:Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; 的格式,

// subscriptionsByEventType 这个集合存放的是? 
// key 是 Event 参数的类 
// value 存放的是 Subscription 的集合列表 
// Subscription 包含两个属性,一个是 subscriber 订阅者(反射执行对象),一个是 SubscriberMethod 注解方法的所有属性参数值
 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // 获取方法参数的 class
        Class<?> eventType = subscriberMethod.eventType;
        // 创建一个 Subscription   subscriber——MainActivity 
        //subscriberMethod——解析好的有注解的方法
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        // 获取订阅了此事件类的所有订阅者信息列表
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            // 线程安全的 ArrayList
            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;
            }
        }
        // 通过 subscriber 获取  List<Class<?>>
        // typesBySubscriber 这个集合存放的是?
        // key 是所有的订阅者
        // value 是所有订阅者里面方法的参数的class
        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<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);
            }
        }
    }

3.EventBus的post().

遍历subscriptionsByEventType,找到符合的方法,然后通过invoke去执行。

  public void post(Object event) {

        // currentPostingThreadState 是一个 ThreadLocal,
        // 他的特点是获取当前线程一份独有的变量数据,不受其他线程影响。
        // 这个在 Handler 里面有过源码分析
        PostingThreadState postingState = currentPostingThreadState.get();
        // postingState 就是获取到的线程独有的变量数据
        List<Object> eventQueue = postingState.eventQueue;
        // 把 post 的事件添加到事件队列
        eventQueue.add(event);
        // 如果没有处在事件发布状态,那么开始发送事件并一直保持发布状态
        if (!postingState.isPosting) {
            // 是否是主线程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            // isPosting = true
            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;
            }
        }
    }

3.1 postSingleEvent()

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        
        //Event:post传入的值, postingState从线程池中拿出来的一份独有的数据
        
        // 得post传入值类型的Class
        Class<?> eventClass = event.getClass();
        // 是否找到订阅者
        boolean subscriptionFound = false;
        // 如果支持事件继承,默认为支持
        if (eventInheritance) {
            // 查找 eventClass 的所有父类和接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 依次向 eventClass 的父类或接口的订阅方法发送事件
                // 只要有一个事件发送成功,返回 true ,那么 subscriptionFound 就为 true
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            // 发送事件
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        // 如果没有订阅者
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

3.2 postSingleEventForEventType()

  private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        //event:text  eventClass:String.class
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 得到Subscription 列表
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            // 遍历 subscriptions
            for (Subscription subscription : subscriptions) {
                //
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                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;
    }

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

3.4 invokeSubscriber 通过反射去执行订阅者的订阅方法。

void invokeSubscriber(Subscription subscription, Object event) {
        //subscription : 封装了MainActivity method ThreadMode Priority Sticky
        //event: post 方法传入的参数
        
        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);
        }
    }

4.0

第二部分:自己动手写,需要做些什么:

1.register

2.unregister

3.

 public void post(Object event) {  //post传入的是一个参数
        // 遍历 subscriptionsByEventType,找到符合的方法调用方法的 method.invoke() 执行。要注意线程切换
        Class<?> eventType = event.getClass();
        // 找到符合的方法调用方法的 method.invoke() 执行
        CopyOnWriteArrayList<Subscription> subscriptions =  subscriptionsByEventType.get(eventType);
        if(subscriptions != null){
            for (Subscription subscription : subscriptions) {
                //将方法和参数都提交给executeMethod去判断然后执行
                executeMethod(subscription,event);
            }
        }
    }

    private void executeMethod(final Subscription subscription, final Object event) {
        ThreadMode threadMode =  subscription.subscriberMethod.threadMode;
        boolean isMainThread = Looper.getMainLooper() == Looper.myLooper();
        switch (threadMode){
            case POSTING:
                invokeMethod(subscription,event);
                break;
            case MAIN:
                if(isMainThread){
                    invokeMethod(subscription,event);
                }else {
                    // 行不行,不行?行?
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            invokeMethod(subscription,event);
                        }
                    });
                }
                break;
            case ASYNC:
                AsyncPoster.enqueue(subscription,event);
                break;
            case BACKGROUND:
                if(!isMainThread){
                    invokeMethod(subscription,event);
                }else {
                    AsyncPoster.enqueue(subscription,event);
                }
                break;
        }
    }

    private void invokeMethod(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

另外附上完整代码的github地址

猜你喜欢

转载自blog.csdn.net/lyfxh1314/article/details/86491901