消息處理之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的原理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM