EventBus深入浅析之基本使用

来源:互联网 发布:各种编程语言的区别 编辑:程序博客网 时间:2024/06/05 07:04

1.EventBus是什么?

EventBus是一个发布/订阅的事件总线;EventBus可以理解为包含:发布者-订阅者-事件-总线;   记忆:订阅者订阅事件到总线,发布者发布事件;订阅者可以订阅多个事件,发布者可以发布任何事件,发布者可以同时是订阅者。

2.EventBus基本使用。

提出需求:
1.两个fragment组成主界面,左边是目录,右边是详情;
2.目录是从网络上获取的;
3. 点击左边条目,右边动态获取条目对应的详情;
示例Demo
传统写法:
1.目录fragment在oncreate方法中开启线程,访问网络获取目录信息。
2.在目录fragment中提供接口,在详情fragment中注册本接口,在左边条目发生点击时回掉本接口,让详情信息发生改变。

代码:

public class ItemListFragment extends ListFragment  {      @Override      public void onCreate(Bundle savedInstanceState)      {          super.onCreate(savedInstanceState);          // Register          EventBus.getDefault().register(this);      }      @Override      public void onDestroy()      {          super.onDestroy();          // Unregister          EventBus.getDefault().unregister(this);      }      @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));      }  }  

onCreate里面进行了事件的订阅,
onDestroy里面进行了事件的取消;
onViewCreated中我们模拟了一个子线程去网络加载数据,获取成功后我们调用了EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));发布了一个事件;
onListItemClick则是ListView的点击事件,我们调用了EventBus.getDefault().post(getListView().getItemAtPosition(position));去发布一个事件,

然后,在 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()));    }

这个方法绑定了数据,可是这个方法是怎么被调用的呢?
我们需要清楚的知道订阅事件和发布事件的规则:

如果方法名以onEvent开头,则代表要订阅一个事件,MainThread意思,这个方法最终要在UI线程执行;当事件发布的时候,这个方法就会被执行。

事件的发布:

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

发布了一个事件,当这个事件发布,我们的onEventMainThread就执行了

现在我们完整的理一下:
在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) ;

public class ItemDetailFragment extends Fragment  {      private TextView tvDetail;      @Override      public void onCreate(Bundle savedInstanceState)      {          super.onCreate(savedInstanceState);          // register          EventBus.getDefault().register(this);      }      @Override      public void onDestroy()      {          super.onDestroy();          // Unregister          EventBus.getDefault().unregister(this);      }      /** 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实参传递进来,我们更新控件。

3.最后

可以利用EventBus尝试做以下操作:
当接收到某个广播,例如短信,在界面上显示。
开启一个Service,在服务器里面启动一个定时线程,不断更新ActivityUI。
等等…之后,你会发现EventBus的魅力!

声明一下:上面两个Fragment的例子是我在网上down到的,做了简单的修改,虽然很简单,但是很能说明问题。

0 0