android開源框架之EventBus

EventBus是個什麼東西?有什麼用?html

EventBus是一個發佈 / 訂閱的事件總線。簡單點說,就是兩人約定好怎麼通訊,一人發佈消息,另一個約定好的人立馬接收到你發的消息。java

用處:相信你們都用過Handle了進行線程通訊,回調方法進行通訊,是否是以爲特麻煩。EventBus就能夠幫減小不少事,無論你在任何地方任何位置發佈一個事件,接收者都能立馬接收到你的消息,不用你考慮android子線程操做UI線程的問題!!!!並且還有個好處,就這這個框架很容易上手!!!android

項目地址:git

 

 

關係:github

data-cke-saved-src=http://www.2cto.com/uploadfile/Collfiles/20150306/2015030609170470.png

訂閱者能夠訂閱多個事件,發送者能夠發佈任何事件,發佈者同時也能夠是訂閱者。面試

具體使用:服務器

訂閱者相關:網絡

註冊訂閱者: EventBus.getDefault().register(this);app

這個方法一般在onCreate方法中進行註冊。框架

解綁訂閱者: EventBus.getDefault().unregister(this);

這個方法一般在onDestroy方法中進行解綁。

約定的收到事件要執行的方法:EventBus已經規定好了使用以下四個方法:

onEvent:若是使用onEvent做爲訂閱函數,那麼該事件在哪一個線程發佈出來的,onEvent就會在這個線程中運行,也就是說發佈事件和接收事件線程在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操做,若是執行耗時操做容易致使事件分發延遲。
onEventMainThread:若是使用onEventMainThread做爲訂閱函數,那麼不論事件是在哪一個線程中發佈出來的,onEventMainThread都會在UI線程中執行,接收事件就會在UI線程中運行,這個在Android中是很是有用的,由於在Android中只能在UI線程中跟新UI,因此在onEvnetMainThread方法中是不能執行耗時操做的。
onEventBackground:若是使用onEventBackgrond做爲訂閱函數,那麼若是事件是在UI線程中發佈出來的,那麼onEventBackground就會在子線程中運行,若是事件原本就是子線程中發佈出來的,那麼onEventBackground函數直接在該子線程中執行。
onEventAsync:使用這個函數做爲訂閱函數,那麼不管事件在哪一個線程發佈,都會建立新的子線程在執行onEventAsync.

例子: public void onEvent(Object object){
Log.e(hongliang,onEvent);
}

當訂閱者收到事件後,就會自動執行上面這四個方法,根據需求寫某個方法就能夠了,若是寫了多個,則都會執行。

或許,你會問,要是多個類都是訂閱者,那究竟是誰收到事件呢?

EventBus是根據這四個方法的參數來決定哪一個類接收事件的,發佈者的參數和某個訂閱者這四個方法的參數同樣,則執行這個訂閱者的這個方法。

 

發佈者相關:

發佈事件: EventBus.getDefault().post( new 一個你本身的事件 );

能夠在任意位置發佈。

注意post方法的參數:EventBus會根據這個參數去找訂閱者那四個方法參數和它一致的執行。

例如:

發佈者:EventBus.getDefault().post( new String(發佈者) );

訂閱者:public void onEvent(String str){
Log.e(hongliang,str);
}

由於post的參數是String ,四個方法中onEvent參數String,因此會這個方法會被執行。

還不明白的能夠參考:

轉載請代表出處:http://blog.csdn.net/lmj623565791/article/details/40794879,本文出自:【張鴻洋的博客】

一、概述

 

最近你們面試說常常被問到EventBus,github上果斷down了一份,地址:https://github.com/greenrobot/EventBus,的確是個不錯的框架,主要用於事件的發佈和訂閱。

EventBus定義:是一個發佈 / 訂閱的事件總線。

這麼說應該包含4個成分:發佈者,訂閱者,事件,總線。

那麼這四者的關係是什麼呢?

很明顯:訂閱者訂閱事件到總線,發送者發佈事件。

大致應該是這樣的關係:

\

訂閱者能夠訂閱多個事件,發送者能夠發佈任何事件,發佈者同時也能夠是訂閱者。

好了,大致瞭解基本的關係之後,咱們經過案例驅動來教你們如何使用;

二、代碼是最好的老師

相信你們對Fragment都有所瞭解,如今咱們的需求是這樣的,兩個Fragment組成主界面,左邊的Fragment是個目錄、即列表,右邊的Fragment是詳細信息面板;

a、目錄的列表是從網絡獲取的。

b、當點擊目錄上的條目時,動態更新詳細信息面板;

效果圖:

\

 

看了這個需求,咱們傳統的作法是:

a、目錄Fragment在onCreate中去開啓線程去訪問網絡獲取數據,獲取完成之後,經過handler去更新界面。

b、在目錄的Fragment中提供一個接口,而後詳細信息面板去註冊這個接口,當發生點擊時,去回調這個接口,讓詳細信息面板發生改變。

其實這種作法也仍是不錯的,可是有了EventBus以後,咱們交互會發生什麼樣的變化呢?拭目以待吧。

首先提一下:

EventBus.getDefault().register(this);//訂閱事件

EventBus.getDefault().post(object);//發佈事件

EventBus.getDefault().unregister(this);//取消訂閱

 

一、MainActivity及其佈局

 

[java] view plaincopy在CODE上查看代碼片加載中...

  1. package com.angeldevil.eventbusdemo;

  2.  

  3. import android.os.Bundle;

  4. import android.support.v4.app.FragmentActivity;

  5.  

  6. public class MainActivity extends FragmentActivity

  7. {

  8. @Override

  9. protected void onCreate(Bundle savedInstanceState)

  10. {

  11. super.onCreate(savedInstanceState);

  12. setContentView(R.layout.activity_main);

  13. }

  14.  

  15. }
    [html] view plaincopy在CODE上查看代碼片加載中...

    1. package com.angeldevil.eventbusdemo;

    2.  

    3. import java.util.ArrayList;

    4. import java.util.List;

    5.  

    6. public class Item

    7. {

    8. public String id;

    9. public String content;

    10.  

    11. public static List

       ITEMS = new ArrayList();

    12. static

    13. {

    14. // Add 6 sample items.

    15. addItem(new Item(1, Item 1));

    16. addItem(new Item(2, Item 2));

    17. addItem(new Item(3, Item 3));

    18. addItem(new Item(4, Item 4));

    19. addItem(new Item(5, Item 5));

    20. addItem(new Item(6, Item 6));

    21. }

    22.  

    23. private static void addItem(Item item)

    24. {

    25. ITEMS.add(item);

    26. }

    27.  

    28. public Item(String id, String content)

    29. {

    30. this.id = id;

    31. this.content = content;

    32. }

    33.  

    34. @Override

    35. public String toString()

    36. {

    37. return content;

    38. }

    39. }

       

       

      [java] view plaincopy在CODE上查看代碼片加載中...

    40. package com.angeldevil.eventbusdemo;

    41.  

    42. import android.os.Bundle;

    43. import android.support.v4.app.Fragment;

    44. import android.view.LayoutInflater;

    45. import android.view.View;

    46. import android.view.ViewGroup;

    47. import android.widget.TextView;

    48. import de.greenrobot.event.EventBus;

    49.  

    50. public class ItemDetailFragment extends Fragment

    51. {

    52.  

    53. private TextView tvDetail;

    54.  

    55. @Override

    56. public void onCreate(Bundle savedInstanceState)

    57. {

    58. super.onCreate(savedInstanceState);

    59. // register

    60. EventBus.getDefault().register(this);

    61. }

    62.  

    63. @Override

    64. public void onDestroy()

    65. {

    66. super.onDestroy();

    67. // Unregister

    68. EventBus.getDefault().unregister(this);

    69. }

    70.  

    71. /** List點擊時會發送些事件,接收到事件後更新詳情 */

    72. public void onEventMainThread(Item item)

    73. {

    74. if (item != null)

    75. tvDetail.setText(item.content);

    76. }

    77.  

    78. @Override

    79. public View onCreateView(LayoutInflater inflater, ViewGroup container,

    80. Bundle savedInstanceState)

    81. {

    82. View rootView = inflater.inflate(R.layout.fragment_item_detail,

    83. container, false);

    84. tvDetail = (TextView) rootView.findViewById(R.id.item_detail);

    85. return rootView;

    86. }

    87. }
      果真不出咱們的所料,真的存在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實參傳遞進來,咱們更新控件。

      四、Event

      這裏還有個事件類:

       

      [java] view plaincopy在CODE上查看代碼片加載中...

    88. package com.angeldevil.eventbusdemo;

    89.  

    90. import java.util.List;

    91.  

    92. public class Event

    93. {

    94. /** 列表加載事件 */

    95. public static class ItemListEvent

    96. {

    97. private List

       items;

    98.  

    99. public ItemListEvent(List

       items)

    100. {

    101. this.items = items;

    102. }

    103.  

    104. public List

       getItems()

    105. {

    106. return items;

    107. }

    108. }

    109.  

    110. } ItemListEvent咱們在ItemListFragment中使用的,做爲的是onEventMainThread中的參數。爲何封裝這麼個類呢?會在以後的EventBus源碼解析中說明。

       

      到此咱們的EventBus的初步用法就介紹完畢了。縱觀整個代碼,木有handler、木有AsynTask,木有接口回調;but,咱們像魔術般的實現了咱們的需求;來告訴我,什麼是耦合,沒見到~~~

      三、EventBus的ThreadMode

      EventBus包含4個ThreadMode:PostThread,MainThread,BackgroundThread,Async

      MainThread咱們已經不陌生了;咱們已經使用過。

      具體的用法,極其簡單,方法名爲:onEventPostThread, onEventMainThread,onEventBackgroundThread,onEventAsync便可

      具體什麼區別呢?

      onEventMainThread表明這個方法會在UI線程執行

      onEventPostThread表明這個方法會在當前發佈事件的線程執行

      BackgroundThread這個方法,若是在非UI線程發佈的事件,則直接執行,和發佈在同一個線程中。若是在UI線程發佈的事件,則加入後臺任務隊列,使用線程池一個接一個調用。

      Async 加入後臺任務隊列,使用線程池調用,注意沒有BackgroundThread中的一個接一個。

       

      四、題外話

      你們能夠利用EventBus嘗試作如下操做:

      當接收到某個廣播,例如短信,在界面上顯示。

      開啓一個Service,在服務器裏面啓動一個定時線程,不斷更新ActivityUI。

      等等...以後,你會發現EventBus的魅力!

       

      聲明一下:上面兩個Fragment的例子是我在網上down到的,作了簡單的修改,雖然很簡單,可是很能說明問題。看包名應該是angeldevil寫的,在此表示感謝。

      順便吐槽一個官方給的例子,什麼性能對比,而後一堆TestCase,不直觀。

       

       

      若是你但願深刻理解Eventbus,請看:Android EventBus源碼解析 帶你深刻理解EventBus,相信能夠爲你解除不少困惑,瞭解該框架的設計之美。

    111. package com.angeldevil.eventbusdemo;

    112.  

    113. import android.os.Bundle;

    114. import android.support.v4.app.ListFragment;

    115. import android.view.View;

    116. import android.widget.ArrayAdapter;

    117. import android.widget.ListView;

    118.  

    119. import com.angeldevil.eventbusdemo.Event.ItemListEvent;

    120.  

    121. import de.greenrobot.event.EventBus;

    122.  

    123. public class ItemListFragment extends ListFragment

    124. {

    125.  

    126. @Override

    127. public void onCreate(Bundle savedInstanceState)

    128. {

    129. super.onCreate(savedInstanceState);

    130. // Register

    131. EventBus.getDefault().register(this);

    132. }

    133.  

    134. @Override

    135. public void onDestroy()

    136. {

    137. super.onDestroy();

    138. // Unregister

    139. EventBus.getDefault().unregister(this);

    140. }

    141.  

    142. @Override

    143. public void onViewCreated(View view, Bundle savedInstanceState)

    144. {

    145. super.onViewCreated(view, savedInstanceState);

    146. // 開啓線程加載列表

    147. new Thread()

    148. {

    149. public void run()

    150. {

    151. try

    152. {

    153. Thread.sleep(2000); // 模擬延時

    154. // 發佈事件,在後臺線程發的事件

    155. EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));

    156. } catch (InterruptedException e)

    157. {

    158. e.printStackTrace();

    159. }

    160. };

    161. }.start();

    162. }

    163.  

    164. public void onEventMainThread(ItemListEvent event)

    165. {

    166. setListAdapter(new ArrayAdapter

      (getActivity(),

    167. android.R.layout.simple_list_item_activated_1,

    168. android.R.id.text1, event.getItems()));

    169. }

    170.  

    171. @Override

    172. public void onListItemClick(ListView listView, View view, int position,

    173. long id)

    174. {

    175. super.onListItemClick(listView, view, position, id);

    176. EventBus.getDefault().post(getListView().getItemAtPosition(position));

    177. }

    178.  

    179. }

       

      ItemListFragment裏面在onCreate裏面進行了事件的訂閱,onDestroy裏面進行了事件的取消;onViewCreated中咱們模擬了一個子線程去網絡加載數據,獲取成功後咱們調用

      了EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));發佈了一個事件;

      onListItemClick則是ListView的點擊事件,咱們調用了EventBus.getDefault().post(getListView().getItemAtPosition(position));去發佈一個事件,

      getListView().getItemAtPosition(position)的類型爲Item類型;

      細心的你必定發現了一些詭異的事,直接new Thread()獲取到數據之後,居然沒有使用handler;咱們界面居然發生了變化,那麼List是什麼時候綁定的數據?

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

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

      應該是這個方法爲List綁定的數據。那麼這個方法是怎麼被調用的呢?

      如今就能夠細談訂閱事件與發佈事件了:

      若是方法名以onEvent開頭,則表明要訂閱一個事件,MainThread意思,這個方法最終要在UI線程執行;當事件發佈的時候,這個方法就會被執行。

      那麼這個事件何時發佈呢?

      咱們的onEventMainThread觸發時機應該在new Thread()執行完成以後,能夠看到子線程執行完成以後,執行了EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));

      意味着發佈了一個事件,當這個事件發佈,咱們的onEventMainThread就執行了,那麼兩者的關聯關係是什麼呢?

      其實和參數的類型,咱們onEventMainThread須要接收一個ItemListEvent ,咱們也發佈了一個ItemListEvent的實例。

      如今咱們完整的理一下:

      在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) ; 是否是呢?咱們去看看。

      三、ItemDetailFragment

       

      [java] view plaincopy在CODE上查看代碼片加載中...

    180. xmlns:tools=http://schemas.android.com/tools

    181. android:layout_width=match_parent

    182. android:layout_height=match_parent

    183. android:baselineAligned=false

    184. android:divider=?android:attr/dividerHorizontal

    185. android:orientation=horizontal

    186. android:showDividers=middle >

    187.  

    188. android:id=@+id/item_list

    189. android:name=com.angeldevil.eventbusdemo.ItemListFragment

    190. android:layout_width=0dip

    191. android:layout_height=match_parent

    192. android:layout_weight=1 />

    193.  

    194. android:id=@+id/item_detail_container

    195. android:name=com.angeldevil.eventbusdemo.ItemDetailFragment

    196. android:layout_width=0dip

    197. android:layout_height=match_parent

    198. android:layout_weight=2 />

    199.  


    200. 能夠看到,咱們MainActvity能夠說沒有一行代碼,佈局文件即兩個Fragment組成;

       

      二、ItemListFragment

      首先看個實體類:

       

      [java] view plaincopy在CODE上查看代碼片加載中...

相關文章
相關標籤/搜索