随笔 - 632  文章 - 17  评论 - 54  阅读 - 93万

仿EventBus做一个简单的基于订阅发布的事件总线

一、概述

  在上一节分析了EventBus的源代码。本节仿照EventBus自己做一个事件总线框架,去掉了一些代码,只保留了核心框架,旨在梳理框架的框架原理,加深对框架流程的理解。

  在贴出源代码之前先把这个自定义的EventBus的功能介绍一下。核心流程还是三个,注册、发布、取消注册(未写AnnotationProcessor部分,如果有需要大家可以自己实现),源码中的类绝大部分分仿照了EventBus原有的类名,只是类里面的内容做了简化调整。如:EventBus类只抽离了、post、register、unregister、subscribe方法等。

  完整源代码下载地址

  下面贴出library结构

  

 

 自己实现的框架其用法和EventBus还是一样的,只是不能发送黏性事假和定义事件的优先级,使用实例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class MainActivity extends AppCompatActivity {
    private Button btn;
    private TextView tv;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
         * 注册观察者对象
         */
        EventBus.getDefault().register(this);
        btn = findViewById(R.id.main_btn);
        tv = findViewById(R.id.main_tv);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                toPost();
            }
        });
 
    }
 
    /**
     * 用于接收post发送过来的事件
     *
     * @param event 具体的事件主体
     */
    @Subscribe
    public void onMessageEvent(MessageEvent event) {
        switch (event.getArg1()) {
            case 0:
                tv.setText("接收小消息为:" + event.getMsg());
                break;
 
        }
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 取消订阅
         */
        EventBus.getDefault().unRegister(this);
    }
 
    /**
     * 发送消息
     */
    public void toPost() {
        MessageEvent event = new MessageEvent();
        event.setArg1(0);
        event.setMsg("杨洛峋小宝宝来了");
        EventBus.getDefault().post(event);
    }
 
}

 

二、源码介绍以及源码截图

  下面提出关键源代码

  EventBus.getDefault().register(subscriber)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
   * 注册
   * 订阅方法
   *
   * @param subscriber
   */
  public void register(Object subscriber) {
      Class clazz = subscriber.getClass();
      List<SubscriberMethod> subscriberMethods = SubscriberMethodFinder.findSubscriberMethods(clazz);
      if (subscriberMethods != null && subscriberMethods.size() > 0) {
          for (SubscriberMethod subscriberMethod : subscriberMethods) {
              subscribe(subscriber, subscriberMethod);
          }
      }
  }
 
  /**
   * 真正的订阅
   *
   * @param subscriber
   * @param subscriberMethod
   */
  private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
      Class eventType = subscriberMethod.getEventType();
      Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
      CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
      if (subscriptions == null) {
          subscriptions = new CopyOnWriteArrayList<>();
          subscriptionsByEventType.put(eventType, subscriptions);
      }
      int size = subscriptions.size();
      for (int i = 0; i <= size; i++) {
          if (i == size) {
              //向订阅集合中加入订阅
              subscriptions.add(i, newSubscription);
              break;
          }
      }
 
      List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
      if (subscribedEvents == null) {
          subscribedEvents = new ArrayList<>();
          typesBySubscriber.put(subscriber, subscribedEvents);
      }
      subscribedEvents.add(eventType);
 
  }

  EventBus.getDefault().post(eventObj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
    * 发送事件方法
    *
    * @param eventObj
    */
   public void post(Object eventObj) {
       PostingThreadState postingThreadState = currentPostingThreadState.get();
       List<Object> queue = postingThreadState.getEventQueue();
       queue.add(eventObj);
       postingThreadState.setMainThread(isMainThread());
       //缺少一个发送事件的线程
       Class<?> clazz = eventObj.getClass();
       List<Subscription> subscriptions = subscriptionsByEventType.get(clazz);
       if (subscriptions != null) {
           //循环遍历Subscriptions,
           for (Subscription subscription : subscriptions) {
               //分发事件
               postToSubscription(subscription, eventObj, postingThreadState);
 
           }
       }
 
   }
 
   /**
    * 返回true为主线程,否则为子线程
    *
    * @return
    */
   private boolean isMainThread() {
       return Looper.myLooper() == Looper.getMainLooper();
   }
 
   /**
    * 对事件进行分发
    *
    * @param subscription
    * @param eventTypeObj
    */
   private void postToSubscription(Subscription subscription, Object eventTypeObj, PostingThreadState postingThreadState) {
       switch (subscription.getSubscriberMethod().getThreadMode()) {
           case POSITION:
               invokeSubscriber(subscription, eventTypeObj);
               break;
           case MAIN:
               if (isMainThread()) {
                   invokeSubscriber(subscription, eventTypeObj);
               } else {
                   mainThreadHandlerPoster.enqueue(subscription, eventTypeObj);
               }
               break;
           case MAIN_ORDERD:
               if (mainThreadHandlerPoster != null) {
                   mainThreadHandlerPoster.enqueue(subscription, eventTypeObj);
               } else {
                   invokeSubscriber(subscription, eventTypeObj);
               }
               break;
           case BACKGROUND:
               if (backgroundPoster != null) {
                   backgroundPoster.enqueue(subscription, eventTypeObj);
               } else {
                   invokeSubscriber(subscription, eventTypeObj);
               }
               break;
           case ASYNC:
               asyncPoster.enqueue(subscription, eventTypeObj);
               break;
       }
   }
 
   /**
    * 执行事件的具体方法
    *
    * @param subscription
    * @param eventTypeObj
    */
   public void invokeSubscriber(Subscription subscription, Object eventTypeObj) {
       try {
           subscription.getSubscriberMethod().getMethod().setAccessible(true);
           subscription.getSubscriberMethod().getMethod().invoke(subscription.getSubscriber(), eventTypeObj);
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InvocationTargetException e) {
           e.printStackTrace();
       }
   }

  EventBus.getDefault().unRegister(subscriber)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
    * 取消注册方法
    * 取消注册其实就清除两个 集合就行了,一个是Subscriptions集合,一个是typesBySubscriber集合
    *
    * @param subscriber
    */
   public void unRegister(Object subscriber) {
       List<Class<?>> eventTypes = typesBySubscriber.get(subscriber);
       if (eventTypes != null) {
           for (Class<?> clazz : eventTypes) {
               CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(clazz);
               for (Subscription subscription : subscriptions) {
                   if (subscriber == subscription.getSubscriber()) {
                       subscriptions.remove(subscription);
                   }
               }
           }
           typesBySubscriber.remove(subscriber);
       }
 
   }

  完整的源代码我发布到了github上欢迎大家下载,地址如下:myeventbuslib

posted on   飘杨......  阅读(418)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示