一、關於EventBus:java
組件通信在Android開發中是不可避免的,隨着業務需求的複雜化,代碼中須要咱們去處理的業務邏輯難度也不斷增大。例如多個Fragment之間的數據傳遞,Service與Activity、Fragment之間的通信,BroadCast與Activity、Fragment之間的通信,各類startActivityForResult的使用,繁雜的操做令咱們所厭倦,在GitHub上找了下解決方案,發現了一個不錯的開源庫EventBus,相信不少作過Android開發的朋友都或多或少對此有所瞭解。android
EventBus是一款針對Android優化的發佈/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息.優勢是開銷小,代碼更優雅。以及將發送者和接收者解耦。git
這是EventBus在GitHub上的開源庫地址:https://github.com/greenrobot/EventBusgithub
EventBus的大致關係是這樣的:訂閱者(Subscriber)經過訂閱事件(Event)到總線,事件發佈者(Publisher)發佈事件(Event)到總線被訂閱者(Subscriber)接收,其實說白了就是軟件設計模式裏的觀察者模式。EventBus在使用的時候就是在合適的地方發佈一個事件,使得註冊了該事件接收的對象就能夠收到通知,進行相應的操做。設計模式
二、初探EventBus:app
文縐縐的文字描述使人厭煩,直接上代碼說話吧,先來看下要實現的效果:ide
看似很簡單的效果,點擊按鈕跳轉界面,利用Intent發送一個消息,而後TextView接收顯示。這是傳統上的作法,若是真是這樣作,那麼寫這篇文章的就徹底沒意義了。其實這裏就是利用到了EventBus,並無用到Intent來傳遞消息。函數
先來看下具體的代碼(記得添加EventBus的引用),而後我再分部來解析:post
1 package com.lcw.rabbit.eventbusdemo.eventbusdemo; 2 3 import android.content.Intent; 4 import android.os.Bundle; 5 import android.support.v7.app.AppCompatActivity; 6 import android.view.View; 7 import android.widget.Button; 8 import android.widget.TextView; 9 10 import de.greenrobot.event.EventBus; 11 12 public class MainActivity extends AppCompatActivity { 13 14 private Button mBt_1; 15 private TextView mTv_1; 16 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 //註冊綁定EventBus 22 EventBus.getDefault().register(this); 23 24 initView(); 25 initAction(); 26 27 } 28 29 private void initAction() { 30 mBt_1.setOnClickListener(new View.OnClickListener() { 31 @Override 32 public void onClick(View v) { 33 startActivity(new Intent(MainActivity.this, SecondActivity.class)); 34 } 35 }); 36 } 37 38 private void initView() { 39 mBt_1 = (Button) findViewById(R.id.bt_1); 40 mTv_1 = (TextView) findViewById(R.id.tv_info1); 41 } 42 43 44 //接收所訂閱的消息 45 public void onEventMainThread(MyEvent myEvent) { 46 if (myEvent.getInfo()!=null) { 47 mTv_1.setText(myEvent.getInfo()); 48 } 49 50 } 51 52 53 @Override 54 protected void onDestroy() { 55 super.onDestroy(); 56 //解綁EventBus 57 EventBus.getDefault().unregister(this); 58 } 59 }
1 package com.lcw.rabbit.eventbusdemo.eventbusdemo; 2 3 import android.os.Bundle; 4 import android.support.v7.app.AppCompatActivity; 5 import android.view.View; 6 import android.widget.Button; 7 import android.widget.Toast; 8 9 import de.greenrobot.event.EventBus; 10 11 public class SecondActivity extends AppCompatActivity { 12 13 private Button mBt_2; 14 15 @Override 16 protected void onCreate(Bundle savedInstanceState) { 17 super.onCreate(savedInstanceState); 18 setContentView(R.layout.activity_second); 19 initView(); 20 initAction(); 21 22 } 23 24 private void initAction() { 25 mBt_2.setOnClickListener(new View.OnClickListener() { 26 @Override 27 public void onClick(View v) { 28 Toast.makeText(SecondActivity.this,"消息已發送",Toast.LENGTH_SHORT).show(); 29 EventBus.getDefault().post(new MyEvent("我是被髮送過來的消息")); 30 31 } 32 }); 33 } 34 35 private void initView() { 36 mBt_2 = (Button) findViewById(R.id.bt_2); 37 } 38 39 40 }
1 package com.lcw.rabbit.eventbusdemo.eventbusdemo; 2 3 /** 4 * Created by Lichenwei 5 * Date: 2015-10-11 6 * Time: 18:23 7 */ 8 public class MyEvent { 9 10 private String info; 11 12 public MyEvent(String info) { 13 this.info = info; 14 } 15 16 public String getInfo() { 17 return info; 18 } 19 20 public void setInfo(String info) { 21 this.info = info; 22 } 23 }
上面的代碼很簡單,這裏只是拋磚引玉並不作太多複雜的操做,你們能夠根據本身的項目需求來添加對應的代碼。優化
三、解析代碼:
一、註冊EventBus:
在添加EventBus的引用後,咱們就能夠對任意類進行註冊綁定和解綁EventBus事件,註冊方法和反註冊方法很簡單,在上面的代碼中就能夠看出來了,分別是register和unregister,這裏的EventBus.getDefault是獲取到EventBus實例的意思(單例)。
1 //註冊綁定EventBus 2 EventBus.getDefault().register(this); 3 //解綁EventBus 4 EventBus.getDefault().unregister(this);
二、EventBus事件:
EventBus很靈活,它對事件不進行任何的限制,也不須要繼承或者實現任何類或者接口,能夠是任意類型的實體類,比如上面代碼提到的MyEvent。
三、EventBus事件發佈者:
有了事件以後,咱們就能夠對事件進行發佈,而後能夠被訂閱這個事件的全部訂閱者所接收。發送事件很簡單,有兩種方法post與postSticky:
1 //當即發送事件 2 EventBus.getDefault().post(Object event); 3 //延遲發送事件 4 EventBus.getDefault().postSticky(Objet event);
四、EventBus事件訂閱者:
EventBus的事件訂閱者能夠是任何已經進行註冊EventBus的類,訂閱者的數量是沒有上限的(很重要,下文會提到),這裏的訂閱有4種方法,這裏都是由onEvent開頭的,有着必定的區別:
一、onEvent:
若是使用onEvent做爲訂閱函數,那麼該事件在哪一個線程發佈出來的,onEvent就會在這個線程中運行,也就是說發佈事件和接收事件線程在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操做,若是執行耗時操做容易致使事件分發延遲。
二、onEventMainThread:
若是使用onEventMainThread做爲訂閱函數,那麼不論事件是在哪一個線程中發佈出來的,onEventMainThread都會在UI線程中執行,接收事件就會在UI線程中運行,這個在Android中是很是有用的,由於在Android中只能在UI線程中跟新UI,因此在onEvnetMainThread方法中是不能執行耗時操做的。
三、onEventBackground:
若是使用onEventBackgrond做爲訂閱函數,那麼若是事件是在UI線程中發佈出來的,那麼onEventBackground就會在子線程中運行,若是事件原本就是子線程中發佈出來的,那麼onEventBackground函數直接在該子線程中執行。
四、onEventAsync:
使用這個函數做爲訂閱函數,那麼不管事件在哪一個線程發佈,都會建立新的子線程在執行onEventAsync。
1 public void onEvent(Object event) {} 2 public void onEventMainThread(Object event) {} 3 public void onEventBackgroundThread(Object event) {} 4 public void onEventAsync(Object event) {}
介紹完EventBus裏的全部角色後,咱們來理一理訂閱/被訂閱流程:
首先,要想成爲事件訂閱者須要先對EventBus進行註冊綁定,而後在本類須要去寫一個以onEvent開頭的方法來接收處理消息事件,再來咱們須要一個自定義的事件可讓事件的發佈者發佈,讓事件的訂閱者接收。事件的發佈能夠經過post方法或者是postSticky方法發佈。
四、EventBus所帶來的一些方便之處:
EventBus是一款針對Android優化的發佈/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息.優勢是開銷小,代碼更優雅。以及將發送者和接收者解耦。這是咱們在文章開頭所介紹過的,這裏就很少說了,說幾個在實際開發中所運用到的地方。
例如:
一、當某個頁面的某些值發生變化的時候,須要去同時去更改多個頁面相對應的值,這時候只要這些類註冊訂閱了該事件,那麼咱們就能夠很輕鬆經過post發送消息來進行通信。
二、某些時候,咱們並不但願發佈出來的Event當即被消費掉,而是等到時機成熟。好比說,在一個詳情頁點贊以後,產生一個事件,這個事件並不當即被消費,而是等用戶退出詳情頁回到商品列表以後,接收到該事件,而後刷新Adapter等。其實這就是以前咱們用startActivityForResult和onActivityResult作的事情。這裏咱們就能夠利用postSticky來實現這樣的機制。
總之,EventBus極大的減輕了咱們各類組件之間的通信複雜度,也大大減小了使用ActivityForResult的麻煩。真實值得極力推薦。
五、理解EventBus
從源碼中咱們能夠知道,當咱們在類中註冊綁定EventBus的時候,它會去掃描當前類並記錄下全部已onEvent開頭的方法,存放在一個Map<Key,Value>中,在事件經過post發佈以後,EventBus會根據post中實參的類型,去Map中查找對應的方法,並找到了對應的Thread,最終利用Java的反射機制去執行咱們的方法。
onEventMainThread表示這個方法會在UI主線程執行。
onEventPostThread表示這個方法會在當前發佈事件的線程中執行。
BackgroundThread表示若是在非UI主線程發佈的事件,則直接執行,和發佈在同一個線程中。若是在UI線程發佈的事件,則加入後臺任務隊列,使用線程池一個接一個調用。
Async 加入後臺任務隊列,使用線程池調用,注意沒有BackgroundThread中的一個接一個。
做者:李晨瑋
出處:http://www.cnblogs.com/lichenwei/本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,往後必有一番做爲!旁邊有「推薦」二字,你就順手把它點了吧,相得準,我分文不收;相不許,你也好回來找我!