消息处理之EventBus ——使用篇
以前的几篇文章简单的介绍了一下UI线程和子线程之间的线程通信利器Handler,以及顺便介绍了一下SyncTask和HeadlerThread。这里介绍另一线程通信利器EventBus。
EventBus是一个开源组件。https://github.com/greenrobot/EventBus,通过线程间事件订阅和分发来完成消息传递,通过这种模式来降低组件之间的耦合度。
多说无益,直接看实例。
1 import android.support.v7.app.AppCompatActivity; 2 import android.os.Bundle; 3 import android.util.Log; 4 import android.view.View; 5 import android.widget.Button; 6 import android.widget.TextView; 7 import org.greenrobot.eventbus.EventBus; 8 import org.greenrobot.eventbus.Subscribe; 9 import org.greenrobot.eventbus.ThreadMode; 10 11 public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 12 13 public TextView myTextView; 14 private Button button0, button1, button2, button3; 15 private TestEventBus testEvent; 16 private int count = 0; 17 @Override 18 public void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 myTextView = (TextView)this.findViewById(R.id.text_view); 22 button0 = (Button)this.findViewById(R.id.post1); 23 button1 = (Button)this.findViewById(R.id.post2); 24 button2 = (Button)this.findViewById(R.id.post3); 25 button3 = (Button)this.findViewById(R.id.post4); 26 button0.setOnClickListener(this); 27 button1.setOnClickListener(this); 28 button2.setOnClickListener(this); 29 button3.setOnClickListener(this); 30 //测试线程启动 31 testEvent = new TestEventBus(); 32 testEvent.start(); 33 //订阅事件 34 EventBus.getDefault().register(this); 35 36 } 37 38 @Override 39 public void onClick(View v) { 40 int id = v.getId(); 41 switch (id){ 42 case R.id.post1: 43 MainEvent event = new MainEvent(); 44 event.post = "come frome UI"; 45 //UI线程中发送MainEvent类型事件 46 EventBus.getDefault().post(event); 47 break; 48 case R.id.post2: 49 new Thread(){ 50 public void run(){ 51 MainEvent event = new MainEvent(); 52 event.post = "come frome Thread1"; 53 //非UI线程中发送MainEvent类型事件 54 EventBus.getDefault().post(event); 55 } 56 }.start(); 57 break; 58 case R.id.post3: 59 ThreadEvent event2 = new ThreadEvent(); 60 event2.post = "come frome Thread2"; 61 //UI线程送ThreadEvent类型事件 62 EventBus.getDefault().post(event2); 63 break; 64 case R.id.post4: 65 new Thread(){ 66 public void run(){ 67 ThreadEvent event = new ThreadEvent(); 68 event.post = "come frome Thread2"; 69 //非UI线程中发送ThreadEvent类型事件 70 EventBus.getDefault().post(event); 71 } 72 }.start(); 73 break; 74 default: 75 break; 76 } 77 } 78 79 @Override 80 protected void onDestroy() { 81 //注销该订阅 82 EventBus.getDefault().unregister(this); 83 testEvent.unregister(); 84 super.onDestroy(); 85 } 86 87 /** 88 * 无论从那个线程发布的事件都会在UI线程中执行 89 * ThreadMode.MAIN 90 * @param event 91 * 对应低版本的onEventMainThread方法 92 */ 93 @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) 94 public void onEventMain(MainEvent event) { 95 if(event != null){ 96 String frome = event.post; 97 myTextView.setText(frome); 98 Log.e("Test", "onEventMainThread = " + frome); 99 } 100 } 101 102 /** 103 * 无论从那个线程发布的事件,都在该线程中执行。 104 * 所以需要注意,不能执行耗时操作,避免ANR 105 * ThreadMode.POSTING 106 * @param event 107 * 对应低版本的onEvent 108 */ 109 @Subscribe(threadMode = ThreadMode.POSTING, sticky = true) 110 public void onEventPost(MainEvent event) { 111 if(event != null){ 112 String frome = event.post; 113 Log.e("Test", "onEventPostThread = " + frome); 114 } 115 } 116 117 /** 118 * 如果事件是从UI线程中发布出来,则在子线程中执行 119 * 如果事件本身是从子线程中出来,则仍然在该子线程中执行 120 * ThreadMode.BACKGROUND 121 * @param event 122 * 对应低版本的onEventBackgroundThread方法 123 */ 124 @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) 125 public void onEventBackground(MainEvent event) { 126 if(event != null){ 127 String frome = event.post; 128 Log.e("Test", "onEventBackgroundThread = " + frome); 129 } 130 } 131 132 /** 133 * 无论事件是从那个线程发布,都会另开一个线程执行 134 * 所以该方法永远不会在UI线程中被执行 135 * ThreadMode.ASYNC 136 * 对应低版本的onEventAsync 137 * @param event 138 */ 139 @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true) 140 public void onEventAsync(MainEvent event) { 141 if(event != null){ 142 String frome = event.post; 143 Log.e("Test", "onEventAsync = " + frome); 144 } 145 } 146 public class MainEvent{ 147 148 public String post = ""; 149 } 150 public class ThreadEvent{ 151 152 public String post = ""; 153 } 154 public class TestEventBus extends Thread{ 155 public TestEventBus(){ 156 //注册订阅 157 EventBus.getDefault().register(this); 158 } 159 public void unregister(){ 160 //注销订阅 161 EventBus.getDefault().unregister(this); 162 } 163 public void run(){ 164 while(true){} 165 } 166 /** 167 * 无论从那个线程发布的事件都会在UI线程中执行 168 * ThreadMode.MAIN 169 * @param event 170 * 对应低版本的onEventMainThread方法 171 */ 172 @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) 173 public void onEventMainT(MainEvent event) { 174 if(event != null){ 175 String frome = event.post; 176 myTextView.setText(frome); 177 Log.e("Test", "onEventMainThread_T = " + frome); 178 } 179 } 180 181 /** 182 * 无论从那个线程发布的事件,都在该线程中执行。 183 * 所以需要注意,不能执行耗时操作,避免ANR 184 * ThreadMode.POSTING 185 * @param event 186 * 对应低版本的onEvent 187 */ 188 @Subscribe(threadMode = ThreadMode.POSTING, sticky = true) 189 public void onEventPostT(MainEvent event) { 190 if(event != null){ 191 String frome = event.post; 192 Log.e("Test", "onEventPostThread_T = " + frome); 193 } 194 } 195 196 /** 197 * 如果事件是从UI线程中发布出来,则在子线程中执行 198 * 如果事件本身是从子线程中出来,则仍然在该子线程中执行 199 * ThreadMode.BACKGROUND 200 * @param event 201 * 对应低版本的onEventBackgroundThread方法 202 */ 203 @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) 204 public void onEventBackgroundT(MainEvent event) { 205 if(event != null){ 206 String frome = event.post; 207 Log.e("Test", "onEventBackgroundThread_T = " + frome); 208 } 209 } 210 211 /** 212 * 无论事件是从那个线程发布,都会另开一个线程执行 213 * 所以该方法永远不会在UI线程中被执行 214 * ThreadMode.ASYNC 215 * 对应低版本的onEventAsync 216 * @param event 217 */ 218 @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true) 219 public void onEventAsyncT(MainEvent event) { 220 if(event != null){ 221 String frome = event.post; 222 Log.e("Test", "onEventAsync_T = " + frome); 223 } 224 } 225 /** 226 * 无论从那个线程发布的事件都会在UI线程中执行 227 * ThreadMode.MAIN 228 * @param event 229 * 对应低版本的onEventMainThread方法 230 */ 231 @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) 232 public void onEventMainT(ThreadEvent event) { 233 if(event != null){ 234 String frome = event.post; 235 myTextView.setText(frome); 236 Log.e("Test", "onEventMainThread_T = " + frome); 237 } 238 } 239 240 /** 241 * 无论从那个线程发布的事件,都在该线程中执行。 242 * 所以需要注意,不能执行耗时操作,避免ANR 243 * ThreadMode.POSTING 244 * @param event 245 * 对应低版本的onEvent 246 */ 247 @Subscribe(threadMode = ThreadMode.POSTING, sticky = true) 248 public void onEventPostT(ThreadEvent event) { 249 if(event != null){ 250 String frome = event.post; 251 Log.e("Test", "onEventPostThread_T = " + frome); 252 } 253 } 254 255 /** 256 * 如果事件是从UI线程中发布出来,则在子线程中执行 257 * 如果事件本身是从子线程中出来,则仍然在该子线程中执行 258 * ThreadMode.BACKGROUND 259 * @param event 260 * 对应低版本的onEventBackgroundThread方法 261 */ 262 @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) 263 public void onEventBackgroundT(ThreadEvent event) { 264 if(event != null){ 265 String frome = event.post; 266 Log.e("Test", "onEventBackgroundThread_T = " + frome); 267 } 268 } 269 270 /** 271 * 无论事件是从那个线程发布,都会另开一个线程执行 272 * 所以该方法永远不会在UI线程中被执行 273 * ThreadMode.ASYNC 274 * 对应低版本的onEventAsync 275 * @param event 276 */ 277 @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true) 278 public void onEventAsyncT(ThreadEvent event) { 279 if(event != null){ 280 String frome = event.post; 281 Log.e("Test", "onEventAsync_T = " + frome); 282 } 283 } 284 } 285 286 }
不好意思,例子有点大啊。但是覆盖已经比较全了。
首先,按照订阅的模式,我们发现在主线程里面有订阅(第34行代码)和退订(第82行代码),那么都订阅了那种类型的事件?根据第94,110,125,140行代码定义的方法可以看出有相同的参数类型MainEvent。
其次,还有一个线程TestEventBus 在第32行开始运行。该线程里也有订阅(157行)和退订(161行),而该线程却订阅了两种类型的事件。一个类型是MainEvent(第173,189,203,219行方法中定义的参数类型),另一个类型是TreadEvent(第232,248,263,277行方法中定义的参数)。
好现在开始运行。
先点击第一个按钮POST1,在主线程中发送一个MainEvent事件,内容为“come frome UI” 执行结果如下:
1 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome UI 2 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome UI 3 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome UI 4 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread = come frome UI 5 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome UI 6 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread = come frome UI 7 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread = come frome UI 8 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync = come frome UI
可以看到凡是订阅了MainEvent类型的方法的地方,无论是在子线程还是UI线程,都会被执行。
说明事件的分发本身不会线程做任何挑剔,只要订阅了,就会分发。
点第二个按钮POST2,在非主线程中发送MainEvent事件,内容为“come frome Thread1”。运行结果如下:
1 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome Thread1 2 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome Thread1 3 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome Thread1 4 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread = come frome Thread1 5 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync = come frome Thread1 6 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread = come frome Thread1 7 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome Thread1 8 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread = come frome Thread1
可以看见,这次结果和从UI线程中发事件结果相同。这说明一点,事件接收者并不挑剔事件是从那个线程发出来。
点第三个按钮POST3,在主线程中发送ThreadEvent事件。内容为“come frome Thread2” 。运行结果如下:
1 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome Thread2 2 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome Thread2 3 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome Thread2 4 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome Thread2
由于主线程里面没有订阅ThreadEvent事件,而TestEventBus订阅了ThreadEvent事件,所以,所以在TestEventBus中做了处理,但是UI线程没有收到该事件。
这说明事件分发者分发一个事件时,只给有能力处理该事件类型的订阅者分发。
第四个按钮POST4,先不点击,可以预估一下运行结果............
貌似好简单,首先进行订阅,然后实现处理方法就可以了。但是有个不好的消息,订阅者的处理方法不一定会在订阅者线程中执行。具体的在哪里执行,可以看到代码注释,这里在详细说明一下。
第一种,在低版本的EventBus沿用的方法是onEventMainThread(Event),在EventBus3.0版本则方法可以任意定义,但是接受事件类型需要在参数中说清楚。此外定义的模式为ThreandMod.MAIN。任何版本EventBus,这都表示无论事件发送者在那个线程,接受者都在主线程中运行
第二种,在低版本的EventBus沿用的方法是onEventBackgroundThread(Event),在EventBus3.0 则定义的模式是ThreadMode.BACKGROUND。 任何版本EventBus,
都表示无论是那个线程发出来的事件,如果该线程是后台线程(非主线程)则在该线程中执行。如果是主线程发出来的,则开启新线程执行。
第三种,在低版本的EventBus沿用的方法是onEvent(Event), 在3.0版本则定义的模式是ThreadMode.POSTING。任何版本的EventBus都表示从那个线程发送的事件,都会由该线程执行。
第四种,在低版本的EventBus沿用的方法是onEventAsync,在3.0版本则定义的模式是ThreadMode.ASYNC。表示无论从那个线程发布出来的事件,都重新开启线程执行。
好了,今天就到这里吧。明天再说EventBus的原理。