以前的幾篇文章簡單的介紹了一下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的原理。