Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android事件總線還能怎麼玩?

Android事件總線還能怎麼玩?

編輯:關於Android編程

顧名思義,AndroidEventBus ( github鏈接 : https://github.com/bboyfeiyu/AndroidEventBus )是一個Android平台的事件總線框架,它簡化了Activity、Fragment、Service等組件之間的交互,很大程度上降低了它們之間的耦合,使我們的代碼更加簡潔,耦合性更低,提升了我們的代碼質量。但它能做的卻不僅限於這些。經過定制,它能完成很多有意思的功能,那麼究竟該怎麼做呢?就讓我們一起往下看吧。

不堪回首的痛

首先,讓我們先來看看這麼一個場景:你是否在開發的過程中遇到過從Activity-A跳轉到Activity-B,然後需要在Activity-B處理完某些工作之後回調Activity-A中的某個函數,但Activity又不能手動創建對象來設置一個Listener的情況?或者遇到在某個Service中更新Activity或Fragment中的界面等組件之間的交互問題……

一經思考,你會發現Android中的Activity、Fragment、Service之間的交互是比較麻煩的,可能我們第一想到的是使用廣播接收器來在它們之間進行交互。如上文所說,在Activity-B中發一個廣播,在Activity-A中注冊一個廣播接收器來接收該廣播。但使用廣播接收器稍顯麻煩,如果你要將一個實體類當作數據在組件之間傳遞,那麼該實體類還得實現序列化接口,這個成本實在有點高!如代碼1所示。

class ActivityA extends Activity {  
        @Override
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);             
              // ActivityA中注冊廣播接收器  
            registerReceiver(new BroadcastReceiver() {                  
                @Override
                public void onReceive(Context context, Intent intent) {  
                    User person = intent.getParcelableExtra("user") ;  
                }
            }, new IntentFilter("my_action")) ;  
        }
        // ......   
    }
    // ActivityB中發布廣播  
    class ActivityB extends Activity {  
        @Override
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);              
            // 發布廣播  
            Intent intent  = new Intent("my_    action");  
            intent.putExtra("user", new User("mr.simple")) ;  
            sendBroadcast(intent);
        }
        // ......   
    }
    // 實體類需要實現序列化  
    class User implements Parcelable {  
        String name ;
        public User(String aName) {  
            name = aName ;
        }
       // 代碼省略  
        @Override
        public void writeToParcel(Parcel dest, int flags) {  
            dest.writeString(name);
        }
    }

代碼1

是不是有很麻煩的感覺?我們再來看一個示例,在開發過程中,我們經常要在子線程中做一些耗時操作,然後將結果更新到UI線程,除了AsyncTask之外,Thread加Handler是我們經常用的手段。如代碼2所示。

class MyActivity extends Activity {          
        Handler mHandler = new Handler () {  
            public void handleMessage(android.os.Message msg) {  
                if ( msg.what == 1 ) {  
                    User user = (User)msg.obj ;
                    // do sth  
                }
            };
        } ;
        @Override
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            // code ......             
            new Thread(  
                new Runnable() {  
                    public void run() {  
                        // do sth  
                        User newUser = new User("simple") ;  
                        Message msg = mHandler.obtainMessage() ;
                        msg.what = 1 ;
                        msg.obj = newUser ;
                        mHandler.sendMessage(msg) ;
                    }
            }).start();
        }
    }

代碼2

是不是依然相當麻煩?當然你也可以使用AsyncTask來簡化操作,但AsyncTask的幾個泛型參數讓你的代碼看起來並不那麼簡潔,因此GitHub上出現了TinyTask、SimpleTask這些開源庫來簡化AsyncTask的使用。而這些,使用AndroidEventBus都可以很好地解決!

下面就讓我們來領悟一下AndroidEventBus的強大魅力吧。

初見AndroidEventBus

使用AndroidEventBus簡單概括只有三個步驟:

  • 將對象注冊到AndroidEventBus中;
  • 使用@Subcriber標注訂閱函數(只能有一個參數);
  • 通過post函數發布事件。

接下來就是注冊訂閱對象,如代碼3所示。

public class MainActivity extends Activity {  
    @Override
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);
        // 將對象注冊到事件總線中, ****** 注意要在onDestory中進行注銷 ****  
        EventBus.getDefault().register(this);  
    }
    @Override
    protected void onDestroy() {  
        super.onDestroy();  
        // ****** 不要忘了進行注銷 ****  
        EventBus.getDefault().unregister(this);  
    }
    // 代碼省略  
}

代碼3

在onCreate中注冊之後,MainActivity就可以添加訂閱函數來接收消息了。需要注意的是在onDestory中需要將MainActivity從事件總線中注銷。通過AndroidEventBus你可以去除Activity、Fragment、Service等組件的回調,減少了耦合,簡化了代碼。

事件訂閱函數

事件訂閱需要使用@Subscriber注解進行標識,且訂閱函數的參數必須為一個。事件總線憑借參數類型和@Subscriber注解的tag值來標識訂閱函數的唯一性。當用戶發布事件時,總線庫會根據事件類型和tag來查找符合要求的訂閱函數,並且將這些訂閱函數執行在對應的線程中。我們先來看看代碼4的訂閱函數示例。

public class MainActivity extends Activity {  
    // 代碼省略   
    @Subcriber(tag = "csuicide")  
    private void csuicideMyself(String msg) {  
        // do sth  
        finish();
    }
    @Subcriber(mode = ThreadMode.MAIN)
    private void toastMsgFromEvent(String msg) {  
        // do sth  
    }
    @Subcriber(tag = "async", mode = ThreadMode.ASYNC)  
    private void executeAsync(final String msg) {  
       // do sth  
    }
    // 代碼省略  
}

代碼4

在代碼4中,我們為MainActivity添加了以下三個訂閱函數:

  • csuicideMyself:該訂閱函數執行在主線程,接收事件的類型為String,tag為csuicide。當用戶發布一個事件類型為String,且tag為csuicide的事件時將會觸發該方法。
  • toastMsgFromEvent:該訂閱函數也是執行在主線程,事件類型為String,且tag為默認。當用戶發布一個事件類型為String,且tag為默認的事件時將會觸發該方法。
  • executeAsync:該訂閱函數也是執行在一個異步線程,事件類型為String,且tag為async。當用戶發布一個事件類型為String,且tag為async的事件時將會觸發該方法。

從上述的描述中我們可以知道,事件接收函數主要有兩個約束:事件類型和tag(類似於Intent中的Action)。添加tag是因為在事件類型一樣時,如果投遞一個消息,那麼單純以事件類型(例如String)作為投遞依據,那麼多個參數為String的訂閱函數將會被觸發,這極大地降低了靈活性。

發布事件

參數1為事件類型,無tag:EventBus.getDefault().post(這是一個執行在異步線程的事件);參數2為tag,tag的類型為String,類似Intent的Action:EventBus.getDefault().post(這是一個執行在異步線程的事件:“async”)。

發布事件時可以構造任意類型的事件,如果沒有tag則該參數可以省略。發布事件後,AndroidEventBus會根據事件類型和tag到已注冊的訂閱對象中查找符合要求的訂閱函數,例如投遞的第二個事件類型為String、tag為async,那麼在MainActivity中符合要求的訂閱函數就是:

@Subcriber(tag = "async", mode = ThreadMode.ASYNC)
 private void executeAsync(final String msg) {
   // do sth
 }

AndroidEventBus的ThreadMode

在上述代碼中有一段代碼是這樣的:

@Subcriber(mode = ThreadMode.MAIN)  
 private void toastMsgFromEvent(String msg) {        
 }

這個mode可是大有來頭,它指定這個事件接收函數執行在哪個線程中。具體有如下三個選項:

  • ThreadMode.MAIN,事件接收函數執行在UI線程;
  • ThreadMode.POST,事件在哪個線程發布,接收函數就執行在哪個線程;
  • ThreadMode.ASYNC,事件執行在一個獨立的異步線程中。

圖1中,事件接收函數就執行在異步線程。通過這幾個線程模型,我們就可以定制接收函數的執行線程。這樣我們就可以使用AndroidEventBus做很多事了。比如發布一個事件,在這個事件接收函數中進行耗時操作;或下載圖片、進行HTTP請求、I/O操作等,以及替換Thread、AsyncTask等組件。不過,AndroidEventBus的功能遠不止於此,下面我們就看看如何進行更高端的操作。

圖1  接收函數執行在異步線程中

還可以怎麼玩?

退出應用的另類實現

在Android應用開發中,有些情況下我們需要可以直接退出程序。但問題是,回退棧中含有其他的Activity存在,直接使用返回鍵並不能退出應用。此時我們常見的做法是再自定義一個Application子類,在子類中維護一個Activity的列表,然後在進入Activity時,將Activity添加到列表中,在Activity銷毀之前將自己從Application子類的列表中移除。在需要退出應用時遍歷Application子類的Activity列表,然後調用每個Activity的finish函數。那我們看看AndroidEventBus怎麼實現這個功能。如代碼5所示。

public class CsuicideActivity extends Activity {  
        @Override
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        // 將對象注冊到事件總線中, ****** 注意要在onDestory中進行注銷 ****  
        EventBus.getDefault().register(this);  
    }
    @Override
    protected void onDestroy() {  
        super.onDestroy();       
        // ****** 不要忘了進行注銷 ****  
        EventBus.getDefault().unregister(this);  
    }
    @Subcriber(tag = "csuicide")  
    private void csuicideMyself(String msg) {  
        finish();
    }
}

代碼5

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved