EventBus實例

一、概述

  • 下載地址

    地址:https://github.com/greenrobot/EventBus,是個不錯的組件間通信框架,主要用於事件的發佈和訂閱。

  • EventBus定義

    它是一個發佈 / 訂閱的事件總線。
    它包含4個成分:發佈者,訂閱者,事件,總線。
    訂閱者可以訂閱多個事件,發送者可以發佈任何事件,發佈者同時也可以是訂閱者。

  • 應用場景

    例如:兩個Fragment組成主界面,左邊的Fragment是個目錄,右邊的Fragment是詳細信息面板;
    a、目錄的列表是從網絡獲取的。
    b、當點擊目錄上的條目時,動態更新詳細信息面板;

    看了這個需求,我們傳統的做法是:
    a、目錄Fragment在onCreate中去開啓線程去訪問網絡獲取數據,獲取完成以後,通過handler去更新界面。
    b、在目錄的Fragment中提供一個接口,然後詳細信息面板去註冊這個接口,當發生點擊時,去回調這個接口,讓詳細信息面板發生改變。

  • EventBus使用

    EventBus.getDefault().register(this);//訂閱事件
    EventBus.getDefault().post(object);//發佈事件
    EventBus.getDefault().unregister(this);//取消訂閱

二、代碼演示

1.MainActivity及其佈局

public class MainActivity extends FragmentActivity  
{  
    @Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
    }  
}  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:baselineAligned="false"  
    android:divider="?android:attr/dividerHorizontal"  
    android:orientation="horizontal"  
    android:showDividers="middle" >
    <fragment  
        android:id="@+id/item_list"  
        android:name="com.angeldevil.eventbusdemo.ItemListFragment"  
        android:layout_width="0dip"  
        android:layout_height="match_parent"  
        android:layout_weight="1" />  
    <fragment  
        android:id="@+id/item_detail_container"  
        android:name="com.angeldevil.eventbusdemo.ItemDetailFragment"  
        android:layout_width="0dip"  
        android:layout_height="match_parent"  
        android:layout_weight="2" />  
</LinearLayout>

可以看到,我們MainActvity可以說沒有一行代碼,佈局文件即兩個Fragment組成;

2.Event事件類

public class Event  
{  
    /** 列表加載事件 */  
    public static class ItemListEvent  
    {  
        private List<Item> items;  

        public ItemListEvent(List<Item> items)  
        {  
            this.items = items;  
        }  

        public List<Item> getItems()  
        {  
            return items;  
        }  
    }  

}  

3. ItemListFragment

public class ItemListFragment extends ListFragment  
{  
    @Override  
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        EventBus.getDefault().register(this);  // Register
    }  

    @Override  
    public void onDestroy()  
    {  
        super.onDestroy();  
        EventBus.getDefault().unregister(this);  // Unregister  
    }  

    @Override  
    public void onViewCreated(View view, Bundle savedInstanceState)  
    {  
        super.onViewCreated(view, savedInstanceState);  
        new Thread()   // 開啓線程加載列表  
        {  
            public void run()  
            {  
                try  
                {  
                    Thread.sleep(2000); // 模擬延時  
                    EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));//發佈事件,在後臺線程發的事件  
                } catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
            };  
        }.start();  
    }  

    public void onEventMainThread(ItemListEvent event)  
    {  
        setListAdapter(new ArrayAdapter<Item>(getActivity(),  
                android.R.layout.simple_list_item_activated_1,  
                android.R.id.text1, event.getItems()));  
    }  

    @Override  
    public void onListItemClick(ListView listView, View view, int position,  
            long id)  
    {  
        super.onListItemClick(listView, view, position, id);  
        EventBus.getDefault().post(getListView().getItemAtPosition(position));  
    }  
}  
  • 說明:
    ItemListFragment裏面在onCreate裏面進行了事件的訂閱,onDestroy裏面進行了事件的取消;onViewCreated中我們模擬了一個子線程去網絡加載數據,獲取成功後我們調用了EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));發佈了一個事件;
    細心的你一定發現了一些詭異的事,直接new Thread()獲取到數據以後,竟然沒有使用handler;我們界面竟然發生了變化,那麼List是何時綁定的數據?

  • 仔細看下代碼,發現這個方法:

public void onEventMainThread(ItemListEvent event)
{
    setListAdapter(new ArrayAdapter<Item>(getActivity(),
            android.R.layout.simple_list_item_activated_1,
            android.R.id.text1, event.getItems()));
}
  • 執行原理
    在onCreate裏面執行 EventBus.getDefault().register(this);意思是讓EventBus掃描當前類,把所有onEvent開頭的方法記錄下來,如何記錄呢?使用Map,Key爲方法的參數類型,Value中包含我們的方法。
    這樣在onCreate執行完成以後,我們的onEventMainThread就已經以鍵值對的方式被存儲到EventBus中了。
    然後當子線程執行完畢,調用EventBus.getDefault().post(new ItemListEvent(Item.ITEMS))時,EventBus會根據post中實參的類型,去Map中查找對於的方法,於是找到了我們的onEventMainThread,最終調用反射去執行我們的方法。

  • 結論
    現在我們在看看代碼,當Item點擊的時候EventBus.getDefault().post(getListView().getItemAtPosition(position));我們同樣發佈了一個事件,參數爲Item;這個事件是爲了讓詳細信息的Fragment去更新數據,不用說,按照上面的推測,詳細信息的Fragment裏面一個有個這樣的方法: public void onEventMainThread(Item item) ;

4. ItemDetailFragment

public class ItemDetailFragment extends Fragment  
{  
    private TextView tvDetail;  

    @Override  
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        EventBus.getDefault().register(this);  // register  
    }  

    @Override  
    public void onDestroy()  
    {  
        super.onDestroy();  
        EventBus.getDefault().unregister(this);  // Unregister  
    }  

    /** List點擊時會發送些事件,接收到事件後更新詳情 */  
    public void onEventMainThread(Item item)  
    {  
        if (item != null)  tvDetail.setText(item.content);  
    }  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)  
    {  
        View rootView = inflater.inflate(R.layout.fragment_item_detail,  container, false);  
        tvDetail = (TextView) rootView.findViewById(R.id.item_detail);  
        return rootView;  
    }  
}
  • 結論:
    果然不出我們的所料,真的存在onEventMainThread(Item item)的方法。當然了,必須在onCreate裏面首先書寫EventBus.getDefault().register(this);讓EventBus掃描再說。
    那麼這個Fragment的流程就是:onCreate時,EventBus掃描當前類,將onEventMainThread以鍵值對的形式進行存儲,鍵爲Item.class ,值爲包含該方法的對象。
    然後當ItemListFragment中Item被點擊時,發佈了一個事件:EventBus.getDefault().post(getListView().getItemAtPosition(position));實參的類型恰好是Item,於是觸發我們的onEventMainThread方法,並把Item實參傳遞進來,我們更新控件。

三、EventBus的ThreadMode

  • 簡介
    EventBus包含4個ThreadMode:PostThread,MainThread,BackgroundThread,Async
    MainThread我們已經不陌生了;我們已經使用過。
    具體的用法,極其簡單,方法名爲:onEventPostThread, onEventMainThread,onEventBackgroundThread,onEventAsync即可

  • 具體什麼區別呢?

    1. onEventMainThread代表這個方法會在UI線程執行
    2. onEventPostThread代表這個方法會在當前發佈事件的線程執行
    3. BackgroundThread這個方法,如果在非UI線程發佈的事件,則直接執行,和發佈在同一個線程中。如果在UI線程發佈的事件,則加入後臺任務隊列,使用線程池一個接一個調用。
    4. Async 加入後臺任務隊列,使用線程池調用,注意沒有BackgroundThread中的一個接一個。
發佈了15 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章