EventBus使用详解

矫情吗;* 2023-07-17 03:00 153阅读 0赞

前言

EventBus是一种用于Android的发布/订阅事件总线。它有很多优点:简化应用组件间的通信;解耦事件的发送者和接收者;避免复杂和容易出错的依赖和生命周期的问题;很快,专门为高性能优化过等等。

基础知识

EventBus使用了发布者/订阅者模式。

EventBus-Publish-Subscribe.png

发布者通过EventBus发布事件,订阅者通过EventBus订阅事件。当发布者发布事件时,订阅该事件的订阅者的事件处理方法将被调用。

使用详解

本文将按照如下顺序来介绍EventBus的使用:

  1. 准备工作
  2. 基本使用
  3. 线程模式
  4. 粘性事件
  5. 事件优先级
  6. 订阅者索引

文中所有的代码都放在了GitHub上:

https://github.com/chongyucaiyan/EventBusDemo

准备工作

首先,在模块的 build.gradle 构建脚本中添加EventBus依赖:

  1. dependencies {
  2. ...
  3. implementation 'org.greenrobot:eventbus:3.1.1'
  4. }
  5. 1
  6. 2
  7. 3
  8. 4

接着,添加EventBus混淆规则。ProGuard工具混淆了方法名,并可能移除那些未被调用的方法。订阅者的事件处理方法没有被直接调用,如果开启了ProGuard工具的压缩功能,那么你必须告诉ProGuard工具保留这些订阅者方法。在模块的 proguard-rules.pro 混淆规则文件中添加如下规则:

  1. # EventBus
  2. -keepattributes *Annotation*
  3. -keepclassmembers class ** {
  4. @org.greenrobot.eventbus.Subscribe <methods>;
  5. }
  6. -keep enum org.greenrobot.eventbus.ThreadMode { *; }
  7. 1
  8. 2
  9. 3
  10. 4
  11. 5
  12. 6

基本使用

EventBus的使用非常简单,主要分为3个步骤:

  1. 定义事件。
  2. 订阅事件。
  3. 发布事件。

第一步,定义事件。事件可以是任意普通的Java对象,没有任何特殊的要求。例如:

  1. public class MessageEvent {
  2. private String message;
  3. public MessageEvent(String message) {
  4. this.message = message;
  5. }
  6. public String getMessage() {
  7. return message;
  8. }
  9. public void setMessage(String message) {
  10. this.message = message;
  11. }
  12. }
  13. 1
  14. 2
  15. 3
  16. 4
  17. 5
  18. 6
  19. 7
  20. 8
  21. 9
  22. 10
  23. 11
  24. 12
  25. 13
  26. 14
  27. 15

第二步,订阅事件。订阅者需要定义事件处理方法(也称为订阅者方法)。当发布对应类型的事件时,该方法将被调用。EventBus 3使用 @Subscribe 注解来定义订阅者方法。方法名可以是任意合法的方法名,参数类型为订阅事件的类型。例如:

  1. @Subscribe(threadMode = ThreadMode.MAIN)
  2. public void onMessageEvent(MessageEvent event) {
  3. ...
  4. }
  5. 1
  6. 2
  7. 3
  8. 4

订阅者还需要在总线上注册,并在不需要时在总线上注销。只有订阅者注册了,它们才会收到事件。在Android中,可以根据Activity或者Fragment的生命周期来注册和注销。例如:

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.activity_main);
  5. initContentView();
  6. // 注册订阅者
  7. EventBus.getDefault().register(this);
  8. }
  9. @Override
  10. protected void onDestroy() {
  11. super.onDestroy();
  12. // 注销订阅者
  13. EventBus.getDefault().unregister(this);
  14. }
  15. 1
  16. 2
  17. 3
  18. 4
  19. 5
  20. 6
  21. 7
  22. 8
  23. 9
  24. 10
  25. 11
  26. 12
  27. 13
  28. 14
  29. 15

第三步,发布事件。在需要的地方发布事件,所有订阅了该类型事件并已注册的订阅者将收到该事件。例如:

  1. // 发布事件
  2. EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
  3. 1
  4. 2

下面是一个例子。订阅事件的代码如下所示:

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  2. private static final String TAG = "MainActivity";
  3. private TextView mTvMessage;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. initContentView();
  9. // 注册订阅者
  10. EventBus.getDefault().register(this);
  11. }
  12. private void initContentView() {
  13. Button btnStart = findViewById(R.id.btn_main_start_activity);
  14. mTvMessage = findViewById(R.id.tv_main_message);
  15. btnStart.setOnClickListener(this);
  16. }
  17. @Override
  18. public void onClick(View v) {
  19. if (v.getId() == R.id.btn_main_start_activity) {
  20. SecondActivity.start(this);
  21. }
  22. }
  23. @Subscribe(threadMode = ThreadMode.MAIN)
  24. public void onMessageEvent(MessageEvent event) {
  25. Log.i(TAG, "message is " + event.getMessage());
  26. // 更新界面
  27. mTvMessage.setText(event.getMessage());
  28. }
  29. @Override
  30. protected void onDestroy() {
  31. super.onDestroy();
  32. // 注销订阅者
  33. EventBus.getDefault().unregister(this);
  34. }
  35. }
  36. 1
  37. 2
  38. 3
  39. 4
  40. 5
  41. 6
  42. 7
  43. 8
  44. 9
  45. 10
  46. 11
  47. 12
  48. 13
  49. 14
  50. 15
  51. 16
  52. 17
  53. 18
  54. 19
  55. 20
  56. 21
  57. 22
  58. 23
  59. 24
  60. 25
  61. 26
  62. 27
  63. 28
  64. 29
  65. 30
  66. 31
  67. 32
  68. 33
  69. 34
  70. 35
  71. 36
  72. 37
  73. 38
  74. 39
  75. 40
  76. 41

MainActivity订阅了MessageEvent事件。当接收到MessageEvent事件时,订阅者方法将打印日志消息,并更新界面上的TextView。

发布事件的代码如下所示:

  1. public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
  2. public static void start(Context context) {
  3. Intent intent = new Intent(context, SecondActivity.class);
  4. context.startActivity(intent);
  5. }
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_second);
  10. initContentView();
  11. }
  12. private void initContentView() {
  13. findViewById(R.id.btn_second_post_event).setOnClickListener(this);
  14. }
  15. @Override
  16. public void onClick(View v) {
  17. if (v.getId() == R.id.btn_second_post_event) {
  18. // 发布事件
  19. EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
  20. }
  21. }
  22. }
  23. 1
  24. 2
  25. 3
  26. 4
  27. 5
  28. 6
  29. 7
  30. 8
  31. 9
  32. 10
  33. 11
  34. 12
  35. 13
  36. 14
  37. 15
  38. 16
  39. 17
  40. 18
  41. 19
  42. 20
  43. 21
  44. 22
  45. 23
  46. 24
  47. 25
  48. 26

当点击发布事件的按钮时,SecondActivity将发布一个MessageEvent事件。

运行应用。点击MainActivity界面上的启动活动按钮来启动SecondActivity,然后点击SecondActivity界面上的发布事件按钮来发布事件。最后,回退到MainActivity,可以看到界面上的TextView的内容已经更新为”Hello EventBus!”,并且应用打印出如下信息:

  1. 12-27 20:59:18.919 24705-24705/com.github.cyc.eventbus.basicusedemo I/MainActivity: message is Hello EventBus!
  2. 1

线程模式

EventBus支持订阅者方法在不同于发布事件所在线程的线程中被调用。你可以使用线程模式来指定调用订阅者方法的线程。EventBus总共支持5种线程模式:

  • ThreadMode.POSTING 订阅者方法将在发布事件所在的线程中被调用。这是 默认的线程模式。事件的传递是同步的,一旦发布事件,所有该模式的订阅者方法都将被调用。这种线程模式意味着最少的性能开销,因为它避免了线程的切换。因此,对于不要求是主线程并且耗时很短的简单任务推荐使用该模式。使用该模式的订阅者方法应该快速返回,以避免阻塞发布事件的线程,这可能是主线程。
  • ThreadMode.MAIN 订阅者方法将在主线程(UI线程)中被调用。因此,可以在该模式的订阅者方法中直接更新UI界面。如果发布事件的线程是主线程,那么该模式的订阅者方法将被直接调用。使用该模式的订阅者方法必须快速返回,以避免阻塞主线程。
  • ThreadMode.MAIN_ORDERED 订阅者方法将在主线程(UI线程)中被调用。因此,可以在该模式的订阅者方法中直接更新UI界面。事件将先进入队列然后才发送给订阅者,所以发布事件的调用将立即返回。这使得事件的处理保持严格的串行顺序。使用该模式的订阅者方法必须快速返回,以避免阻塞主线程。
  • ThreadMode.BACKGROUND 订阅者方法将在后台线程中被调用。如果发布事件的线程不是主线程,那么订阅者方法将直接在该线程中被调用。如果发布事件的线程是主线程,那么将使用一个单独的后台线程,该线程将按顺序发送所有的事件。使用该模式的订阅者方法应该快速返回,以避免阻塞后台线程。
  • ThreadMode.ASYNC 订阅者方法将在一个单独的线程中被调用。因此,发布事件的调用将立即返回。如果订阅者方法的执行需要一些时间,例如网络访问,那么就应该使用该模式。避免触发大量的长时间运行的订阅者方法,以限制并发线程的数量。EventBus使用了一个线程池来有效地重用已经完成调用订阅者方法的线程。

下面是一个例子。订阅事件的代码如下所示:

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  2. private static final String TAG = "MainActivity";
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. initContentView();
  8. // 注册订阅者
  9. EventBus.getDefault().register(this);
  10. }
  11. private void initContentView() {
  12. findViewById(R.id.btn_main_start_activity).setOnClickListener(this);
  13. }
  14. @Override
  15. public void onClick(View v) {
  16. if (v.getId() == R.id.btn_main_start_activity) {
  17. SecondActivity.start(this);
  18. }
  19. }
  20. @Subscribe(threadMode = ThreadMode.POSTING)
  21. public void onMessageEventPosting(MessageEvent event) {
  22. Log.i(TAG, "onMessageEventPosting(), current thread is " + Thread.currentThread().getName());
  23. }
  24. @Subscribe(threadMode = ThreadMode.MAIN)
  25. public void onMessageEventMain(MessageEvent event) {
  26. Log.i(TAG, "onMessageEventMain(), current thread is " + Thread.currentThread().getName());
  27. }
  28. @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
  29. public void onMessageEventMainOrdered(MessageEvent event) {
  30. Log.i(TAG, "onMessageEventMainOrdered(), current thread is " + Thread.currentThread().getName());
  31. }
  32. @Subscribe(threadMode = ThreadMode.BACKGROUND)
  33. public void onMessageEventBackground(MessageEvent event) {
  34. Log.i(TAG, "onMessageEventBackground(), current thread is " + Thread.currentThread().getName());
  35. }
  36. @Subscribe(threadMode = ThreadMode.ASYNC)
  37. public void onMessageEventAsync(MessageEvent event) {
  38. Log.i(TAG, "onMessageEventAsync(), current thread is " + Thread.currentThread().getName());
  39. }
  40. @Override
  41. protected void onDestroy() {
  42. super.onDestroy();
  43. // 注销订阅者
  44. EventBus.getDefault().unregister(this);
  45. }
  46. }
  47. 1
  48. 2
  49. 3
  50. 4
  51. 5
  52. 6
  53. 7
  54. 8
  55. 9
  56. 10
  57. 11
  58. 12
  59. 13
  60. 14
  61. 15
  62. 16
  63. 17
  64. 18
  65. 19
  66. 20
  67. 21
  68. 22
  69. 23
  70. 24
  71. 25
  72. 26
  73. 27
  74. 28
  75. 29
  76. 30
  77. 31
  78. 32
  79. 33
  80. 34
  81. 35
  82. 36
  83. 37
  84. 38
  85. 39
  86. 40
  87. 41
  88. 42
  89. 43
  90. 44
  91. 45
  92. 46
  93. 47
  94. 48
  95. 49
  96. 50
  97. 51
  98. 52
  99. 53
  100. 54
  101. 55

MainActivity订阅了MessageEvent事件,定义了5个不同线程模式的订阅者方法。当接收到MessageEvent事件时,订阅者方法将打印当前所在的线程名。

发布事件的代码如下所示:

  1. public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
  2. public static void start(Context context) {
  3. Intent intent = new Intent(context, SecondActivity.class);
  4. context.startActivity(intent);
  5. }
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_second);
  10. initContentView();
  11. }
  12. private void initContentView() {
  13. findViewById(R.id.btn_second_post_event).setOnClickListener(this);
  14. }
  15. @Override
  16. public void onClick(View v) {
  17. if (v.getId() == R.id.btn_second_post_event) {
  18. // 发布事件
  19. new Thread("posting") {
  20. @Override
  21. public void run() {
  22. EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
  23. }
  24. }.start();
  25. }
  26. }
  27. }
  28. 1
  29. 2
  30. 3
  31. 4
  32. 5
  33. 6
  34. 7
  35. 8
  36. 9
  37. 10
  38. 11
  39. 12
  40. 13
  41. 14
  42. 15
  43. 16
  44. 17
  45. 18
  46. 19
  47. 20
  48. 21
  49. 22
  50. 23
  51. 24
  52. 25
  53. 26
  54. 27
  55. 28
  56. 29
  57. 30
  58. 31
  59. 32

当点击发布事件的按钮时,SecondActivity将在一个名为”posting”的线程中发布一个MessageEvent事件。

运行应用。点击MainActivity界面上的启动活动按钮来启动SecondActivity,然后点击SecondActivity界面上的发布事件按钮来发布事件。应用打印出如下信息:

  1. 12-27 22:12:05.745 6003-6117/com.github.cyc.eventbus.threadmodedemo I/MainActivity: onMessageEventBackground(), current thread is posting
  2. 12-27 22:12:05.746 6003-6117/com.github.cyc.eventbus.threadmodedemo I/MainActivity: onMessageEventPosting(), current thread is posting
  3. 12-27 22:12:05.752 6003-6003/com.github.cyc.eventbus.threadmodedemo I/MainActivity: onMessageEventMain(), current thread is main
  4. 12-27 22:12:05.752 6003-6003/com.github.cyc.eventbus.threadmodedemo I/MainActivity: onMessageEventMainOrdered(), current thread is main
  5. 12-27 22:12:05.754 6003-6118/com.github.cyc.eventbus.threadmodedemo I/MainActivity: onMessageEventAsync(), current thread is pool-1-thread-1
  6. 1
  7. 2
  8. 3
  9. 4
  10. 5

粘性事件

如果先发布了事件,然后有订阅者订阅了该事件,那么除非再次发布该事件,否则订阅者将永远接收不到该事件。此时,可以使用粘性事件。发布一个粘性事件之后,EventBus将在内存中缓存该粘性事件。当有订阅者订阅了该粘性事件,订阅者将接收到该事件。

订阅和发布一个粘性事件的示例代码如下所示:

  1. // 订阅粘性事件
  2. @Subscribe(sticky = true)
  3. public void onMessageEvent(MessageEvent event) {
  4. ...
  5. }
  6. // 发布粘性事件
  7. EventBus.getDefault().postSticky(new MessageEvent("Hello EventBus!"));
  8. 1
  9. 2
  10. 3
  11. 4
  12. 5
  13. 6
  14. 7
  15. 8

发布一个粘性事件之后,EventBus将一直缓存该粘性事件。如果想要移除粘性事件,那么可以使用如下方法:

  1. // 移除指定的粘性事件
  2. removeStickyEvent(Object event);
  3. // 移除指定类型的粘性事件
  4. removeStickyEvent(Class<T> eventType);
  5. // 移除所有的粘性事件
  6. removeAllStickyEvents();
  7. 1
  8. 2
  9. 3
  10. 4
  11. 5
  12. 6
  13. 7
  14. 8

下面是一个例子。发布粘性事件的代码如下所示:

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. initContentView();
  7. }
  8. private void initContentView() {
  9. findViewById(R.id.btn_main_post_event).setOnClickListener(this);
  10. findViewById(R.id.btn_main_start_activity).setOnClickListener(this);
  11. }
  12. @Override
  13. public void onClick(View v) {
  14. switch (v.getId()) {
  15. case R.id.btn_main_post_event:
  16. // 发布粘性事件
  17. EventBus.getDefault().postSticky(new MessageEvent("Hello EventBus!"));
  18. break;
  19. case R.id.btn_main_start_activity:
  20. SecondActivity.start(this);
  21. break;
  22. default:
  23. break;
  24. }
  25. }
  26. }
  27. 1
  28. 2
  29. 3
  30. 4
  31. 5
  32. 6
  33. 7
  34. 8
  35. 9
  36. 10
  37. 11
  38. 12
  39. 13
  40. 14
  41. 15
  42. 16
  43. 17
  44. 18
  45. 19
  46. 20
  47. 21
  48. 22
  49. 23
  50. 24
  51. 25
  52. 26
  53. 27
  54. 28
  55. 29
  56. 30
  57. 31

当点击发布粘性事件的按钮时,MainActivity将发布一个MessageEvent粘性事件。

订阅粘性事件的代码如下所示:

  1. public class SecondActivity extends AppCompatActivity {
  2. private static final String TAG = "SecondActivity";
  3. private TextView mTvMessage;
  4. public static void start(Context context) {
  5. Intent intent = new Intent(context, SecondActivity.class);
  6. context.startActivity(intent);
  7. }
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_second);
  12. initContentView();
  13. // 注册订阅者
  14. EventBus.getDefault().register(this);
  15. }
  16. private void initContentView() {
  17. mTvMessage = findViewById(R.id.tv_second_message);
  18. }
  19. @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
  20. public void onMessageEvent(MessageEvent event) {
  21. Log.i(TAG, "message is " + event.getMessage());
  22. // 更新界面
  23. mTvMessage.setText(event.getMessage());
  24. // 移除粘性事件
  25. EventBus.getDefault().removeStickyEvent(event);
  26. }
  27. @Override
  28. protected void onDestroy() {
  29. super.onDestroy();
  30. // 注销订阅者
  31. EventBus.getDefault().unregister(this);
  32. }
  33. }
  34. 1
  35. 2
  36. 3
  37. 4
  38. 5
  39. 6
  40. 7
  41. 8
  42. 9
  43. 10
  44. 11
  45. 12
  46. 13
  47. 14
  48. 15
  49. 16
  50. 17
  51. 18
  52. 19
  53. 20
  54. 21
  55. 22
  56. 23
  57. 24
  58. 25
  59. 26
  60. 27
  61. 28
  62. 29
  63. 30
  64. 31
  65. 32
  66. 33
  67. 34
  68. 35
  69. 36
  70. 37
  71. 38
  72. 39

SecondActivity订阅了MessageEvent粘性事件。当接收到MessageEvent粘性事件时,订阅者方法将打印日志消息,并更新界面上的TextView,最后移除该粘性事件。

运行应用。先点击MainActivity界面上的发布粘性事件按钮来发布粘性事件,然后点击启动活动按钮来启动SecondActivity。可以看到SecondActivity界面上的TextView的内容更新为”Hello EventBus!”,并且应用打印出如下信息:

  1. 12-27 22:52:16.975 7684-7684/com.github.cyc.eventbus.stickyeventdemo I/SecondActivity: message is Hello EventBus!
  2. 1

事件优先级

EventBus支持在定义订阅者方法时指定事件传递的优先级。默认情况下,订阅者方法的事件传递优先级为0。数值越大,优先级越高。在相同的线程模式下,更高优先级的订阅者方法将优先接收到事件。注意:优先级只有在相同的线程模式下才有效。

指定事件传递优先级的示例代码如下所示:

  1. @Subscribe(priority = 1)
  2. public void onMessageEvent(MessageEvent event) {
  3. ...
  4. }
  5. 1
  6. 2
  7. 3
  8. 4

你可以在高优先级的订阅者方法接收到事件之后取消事件的传递。此时,低优先级的订阅者方法将不会接收到该事件。注意: 订阅者方法只有在线程模式为ThreadMode.POSTING时,才可以取消一个事件的传递。

取消事件传递的示例代码如下所示:

  1. @Subscribe(threadMode = ThreadMode.POSTING, priority = 1)
  2. public void onMessageEvent(MessageEvent event) {
  3. ...
  4. // 取消事件传递
  5. EventBus.getDefault().cancelEventDelivery(event);
  6. }
  7. 1
  8. 2
  9. 3
  10. 4
  11. 5
  12. 6

下面是一个例子。订阅事件的代码如下所示:

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  2. private static final String TAG = "MainActivity";
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. initContentView();
  8. // 注册订阅者
  9. EventBus.getDefault().register(this);
  10. }
  11. private void initContentView() {
  12. findViewById(R.id.btn_main_start_activity).setOnClickListener(this);
  13. }
  14. @Override
  15. public void onClick(View v) {
  16. if (v.getId() == R.id.btn_main_start_activity) {
  17. SecondActivity.start(this);
  18. }
  19. }
  20. @Subscribe(threadMode = ThreadMode.POSTING, priority = 1)
  21. public void onMessageEvent1(MessageEvent event) {
  22. Log.i(TAG, "onMessageEvent1(), message is " + event.getMessage());
  23. }
  24. @Subscribe(threadMode = ThreadMode.POSTING, priority = 2)
  25. public void onMessageEvent2(MessageEvent event) {
  26. Log.i(TAG, "onMessageEvent2(), message is " + event.getMessage());
  27. // 取消事件
  28. EventBus.getDefault().cancelEventDelivery(event);
  29. }
  30. @Subscribe(threadMode = ThreadMode.POSTING, priority = 3)
  31. public void onMessageEvent3(MessageEvent event) {
  32. Log.i(TAG, "onMessageEvent3(), message is " + event.getMessage());
  33. }
  34. @Subscribe(threadMode = ThreadMode.POSTING, priority = 4)
  35. public void onMessageEvent4(MessageEvent event) {
  36. Log.i(TAG, "onMessageEvent4(), message is " + event.getMessage());
  37. }
  38. @Subscribe(threadMode = ThreadMode.POSTING, priority = 5)
  39. public void onMessageEvent5(MessageEvent event) {
  40. Log.i(TAG, "onMessageEvent5(), message is " + event.getMessage());
  41. }
  42. @Override
  43. protected void onDestroy() {
  44. super.onDestroy();
  45. // 注销订阅者
  46. EventBus.getDefault().unregister(this);
  47. }
  48. }
  49. 1
  50. 2
  51. 3
  52. 4
  53. 5
  54. 6
  55. 7
  56. 8
  57. 9
  58. 10
  59. 11
  60. 12
  61. 13
  62. 14
  63. 15
  64. 16
  65. 17
  66. 18
  67. 19
  68. 20
  69. 21
  70. 22
  71. 23
  72. 24
  73. 25
  74. 26
  75. 27
  76. 28
  77. 29
  78. 30
  79. 31
  80. 32
  81. 33
  82. 34
  83. 35
  84. 36
  85. 37
  86. 38
  87. 39
  88. 40
  89. 41
  90. 42
  91. 43
  92. 44
  93. 45
  94. 46
  95. 47
  96. 48
  97. 49
  98. 50
  99. 51
  100. 52
  101. 53
  102. 54
  103. 55
  104. 56
  105. 57

MainActivity订阅了MessageEvent事件,定义了5个不同优先级的订阅者方法。当接收到MessageEvent事件时,订阅者方法将打印日志消息。优先级为2的订阅者方法在接收到事件之后取消了事件的传递。

发布事件的代码如下所示:

  1. public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
  2. public static void start(Context context) {
  3. Intent intent = new Intent(context, SecondActivity.class);
  4. context.startActivity(intent);
  5. }
  6. @Override protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState); setContentView(R.layout.activity_second);
  8. initContentView();
  9. }
  10. private void initContentView() {
  11. findViewById(R.id.btn_second_post_event).setOnClickListener(this);
  12. }
  13. @Override
  14. public void onClick(View v) {
  15. if (v.getId() == R.id.btn_second_post_event) {
  16. // 发布事件
  17. EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
  18. }
  19. }
  20. }
  21. 1
  22. 2
  23. 3
  24. 4
  25. 5
  26. 6
  27. 7
  28. 8
  29. 9
  30. 10
  31. 11
  32. 12
  33. 13
  34. 14
  35. 15
  36. 16
  37. 17
  38. 18
  39. 19
  40. 20
  41. 21
  42. 22
  43. 23
  44. 24
  45. 25
  46. 26

当点击发布事件的按钮时,SecondActivity将发布一个MessageEvent事件。

运行应用。点击MainActivity界面上的启动活动按钮来启动SecondActivity,然后点击SecondActivity界面上的发布事件按钮来发布事件。应用打印出如下信息:

  1. 12-28 01:03:27.751 22428-22428/com.github.cyc.eventbus.eventprioritydemo I/MainActivity: onMessageEvent5(), message is Hello EventBus!
  2. 12-28 01:03:27.751 22428-22428/com.github.cyc.eventbus.eventprioritydemo I/MainActivity: onMessageEvent4(), message is Hello EventBus!
  3. 12-28 01:03:27.751 22428-22428/com.github.cyc.eventbus.eventprioritydemo I/MainActivity: onMessageEvent3(), message is Hello EventBus!
  4. 12-28 01:03:27.752 22428-22428/com.github.cyc.eventbus.eventprioritydemo I/MainActivity: onMessageEvent2(), message is Hello EventBus!
  5. 1
  6. 2
  7. 3
  8. 4

订阅者索引

默认情况下,EventBus在查找订阅者方法时采用的是反射。订阅者索引是EventBus 3的一个新特性。它可以加速订阅者的注册,是一个可选的优化。订阅者索引的原理是:使用EventBus的注解处理器在应用构建期间创建订阅者索引类,该类包含了订阅者和订阅者方法的相关信息。EventBus官方推荐在Android中使用订阅者索引以获得最佳的性能。

要开启订阅者索引的生成,你需要在构建脚本中使用annotationProcessor属性将EventBus的注解处理器添加到应用的构建中,还要设置一个eventBusIndex参数来指定要生成的订阅者索引的完全限定类名。

我们在前面的基本使用的那个例子上进行修改。首先,修改模块下的build.gradle构建脚本:

  1. android {
  2. defaultConfig {
  3. ...
  4. javaCompileOptions {
  5. annotationProcessorOptions {
  6. arguments = [eventBusIndex: 'com.github.cyc.eventbus.subscriberindexdemo.MyEventBusIndex']
  7. }
  8. }
  9. }
  10. ...
  11. }
  12. dependencies {
  13. ...
  14. compile 'org.greenrobot:eventbus:3.1.1'
  15. annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
  16. }
  17. 1
  18. 2
  19. 3
  20. 4
  21. 5
  22. 6
  23. 7
  24. 8
  25. 9
  26. 10
  27. 11
  28. 12
  29. 13
  30. 14
  31. 15
  32. 16
  33. 17

然后,build一下工程。EventBus注解处理器将为你生成一个订阅者索引类。如下所示:

  1. package com.github.cyc.eventbus.subscriberindexdemo;
  2. import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
  3. import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
  4. import org.greenrobot.eventbus.meta.SubscriberInfo;
  5. import org.greenrobot.eventbus.meta.SubscriberInfoIndex;
  6. import org.greenrobot.eventbus.ThreadMode;
  7. import java.util.HashMap;
  8. import java.util.Map;
  9. /** This class is generated by EventBus, do not edit. */
  10. public class MyEventBusIndex implements SubscriberInfoIndex {
  11. private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
  12. static {
  13. SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
  14. putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
  15. new SubscriberMethodInfo("onMessageEvent", MessageEvent.class, ThreadMode.MAIN),
  16. }));
  17. }
  18. private static void putIndex(SubscriberInfo info) {
  19. SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
  20. }
  21. @Override
  22. public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
  23. SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
  24. if (info != null) {
  25. return info;
  26. } else {
  27. return null;
  28. }
  29. }
  30. }
  31. 1
  32. 2
  33. 3
  34. 4
  35. 5
  36. 6
  37. 7
  38. 8
  39. 9
  40. 10
  41. 11
  42. 12
  43. 13
  44. 14
  45. 15
  46. 16
  47. 17
  48. 18
  49. 19
  50. 20
  51. 21
  52. 22
  53. 23
  54. 24
  55. 25
  56. 26
  57. 27
  58. 28
  59. 29
  60. 30
  61. 31
  62. 32
  63. 33
  64. 34
  65. 35
  66. 36
  67. 37
  68. 38
  69. 39

最后,在应用自定义的Application类的onCreate()方法中将订阅者索引类添加到EventBus中,并将该EventBus设置成默认的EventBus。示例代码如下所示:

  1. public class MyApplication extends Application {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. // 配置EventBus
  6. EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
  7. }
  8. }
  9. 1
  10. 2
  11. 3
  12. 4
  13. 5
  14. 6
  15. 7
  16. 8
  17. 9

运行应用。点击MainActivity界面上的启动活动按钮来启动SecondActivity,然后点击SecondActivity界面上的发布事件按钮来发布事件。最后,回退到MainActivity,可以看到界面上的TextView的内容已经更新为”Hello EventBus!”,并且应用打印出如下信息:

  1. 12-28 02:06:57.365 11335-11335/com.github.cyc.eventbus.subscriberindexdemo I/MainActivity: message is Hello EventBus!
  2. 1

源码分析

EventBus的源码分析可以阅读下面这篇文章:

EventBus源码分析

总结

EventBus是一种用于Android的发布/订阅事件总线。使用EventBus可以简化应用组件间的通信,可以解耦事件的发送者和接收者。

参考

  • EventBus 3.1.1
  • http://greenrobot.org/eventbus/
  • https://github.com/greenrobot/EventBus

发表评论

表情:
评论列表 (有 0 条评论,153人围观)

还没有评论,来说两句吧...

相关阅读

    相关 EventBus使用详解

    前言 EventBus是一种用于Android的发布/订阅事件总线。它有很多优点:简化应用组件间的通信;解耦事件的发送者和接收者;避免复杂和容易出错的依赖和生命周期的问题

    相关 EventBus使用详解

    前言 EventBus是一种用于Android的发布/订阅事件总线。它有很多优点:简化应用组件间的通信;解耦事件的发送者和接收者;避免复杂和容易出错的依赖和生命周期的问题

    相关 EventBus的基本使用

    【 EventBus是一款本地组件间通信框架。在大型项目的Activities,fragments,Threads,Services都可以看到它的使用场景,尽管EventBu

    相关 EventBus使用详解

    > > 前言:EventBus出来已经有一段时间了,github上面也有很多开源项目中使用了EventBus。所以抽空学习顺便整理了一下。目前EventBus最新版本是3

    相关 Guava EventBus 使用

    Guava EventBus 使用 EventBus 是 Google Guava 提供的消息发布-订阅类库,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现,