一、概述
下載地址
地址: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即可具體什麼區別呢?
- onEventMainThread代表這個方法會在UI線程執行
- onEventPostThread代表這個方法會在當前發佈事件的線程執行
- BackgroundThread這個方法,如果在非UI線程發佈的事件,則直接執行,和發佈在同一個線程中。如果在UI線程發佈的事件,則加入後臺任務隊列,使用線程池一個接一個調用。
- Async 加入後臺任務隊列,使用線程池調用,注意沒有BackgroundThread中的一個接一個。