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上查看代码片加载中...