之前的幾篇文章簡單的介紹了一下UI線程和子線程之間的線程通訊利器Handler,以及順便介紹了一下SyncTask和HeadlerThread。這裏介紹另外一線程通訊利器EventBus。android
EventBus是一個開源組件。https://github.com/greenrobot/EventBus,經過線程間事件訂閱和分發來完成消息傳遞,經過這種模式來下降組件之間的耦合度。git
多說無益,直接看實例。github
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 }
很差意思,例子有點大啊。可是覆蓋已經比較全了。app
首先,按照訂閱的模式,咱們發如今主線程裏面有訂閱(第34行代碼)和退訂(第82行代碼),那麼都訂閱了那種類型的事件?根據第94,110,125,140行代碼定義的方法能夠看出有相同的參數類型MainEvent。ide
其次,還有一個線程TestEventBus 在第32行開始運行。該線程裏也有訂閱(157行)和退訂(161行),而該線程卻訂閱了兩種類型的事件。一個類型是MainEvent(第173,189,203,219行方法中定義的參數類型),另外一個類型是TreadEvent(第232,248,263,277行方法中定義的參數)。post
好如今開始運行。測試
先點擊第一個按鈕POST1,在主線程中發送一個MainEvent事件,內容爲「come frome UI」 執行結果以下:this
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線程,都會被執行。spa
說明事件的分發自己不會線程作任何挑剔,只要訂閱了,就會分發。線程
點第二個按鈕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的原理。