3.0EventBus使用

来源:互联网 发布:内存涨价 知乎 编辑:程序博客网 时间:2024/05/22 09:52
EventBus 是典型的观察者模式 EventBus是消息发送者 注册的类是消息订阅者 (内部会根据订阅者接受类型进行分发)  
好处  代码简洁 降低了代码(发布者和阅定者)的耦合度
1 倒入jar包 EVENTBus

2 发送消息 
  Object object = new Object();
  EventBus.getDefault().post(object);

3 接受消息  接收消息的类需要先注册   
      一般在类的初始化时候 (onCreate()方法)注册就行 了 EventBus.getDefault().register(this);

  接受消息的页面实现(共有四个函数,各功能不同分别 是PostThread(默认)、MainThread、BackgroundThread与Async。)

   当接受订阅数据 时在方法上添加注解就可以了
  1. @Subscribe
  2. public void onReceivePlayServic(PlayService playService) {
  3. this.playService = playService;
  4. }
  5. @Subscribe(threadMode = ThreadMode.PostThread)
  6. public void ****(接受消息的类型){
  7. ~~~~~~~~
  8. }
   3.0之后,消息处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为PostThread),四种线程模型, 
    注意  事件处理函数的访问权限必须为public,否则会报异常。

4 注销消息 需要在销毁地方法中进行 onDestroy中进行注销 EventBus.getDefault().unregister(this);

具体使用 举栗子 
        以今天将的手机影音为例子
   发送消息
  1. PlayService extends Service{
  2. @Override
  3. public int onStartCommand(Intent intent, int flags, int startId) {
  4. EventBus.getDefault().post(this); //发送消息
  5. // 读取持久化的播放模式
  6. currentPlayMode = sp.getInt(Keys.PLAY_MODE, PLAY_MODE_ORDER);
  7. int what = intent.getIntExtra(Keys.WHAT, -1);
  8. switch (what) {
  9. case TYPE_NOTIFICATION_PRE: // 如果点击了通知的上一首按钮
  10. pre();
  11. break;
  12. case TYPE_NOTIFICATION_NEXT: // 如果点击了通知的下一首按钮
  13. next();
  14. break;
  15. case TYPE_NOTIFICATION_ROOT: // 如果点击了通知的根容器
  16. ui.updateUi(currentAudioItem);
  17. break;
  18. default: // 从正常播放界面跳转过来的
  19. // 取出音频数据
  20. items = (ArrayList<AudioItem>) intent.getSerializableExtra(Keys.ITEMS);
  21. currentPosition = intent.getIntExtra(Keys.CURRENT_POSITION, -1);
  22. openAudio();
  23. break;
  24. }
  25. return super.onStartCommand(intent, flags, startId);
  26. }
  27. }
阅定
  1. AudioPlayerActivity 初始化方法中 注册
  2. public class AudioPlayerActivity extends BaseActivity {
  3. @Override
  4. public void initView() {
  5. EventBus.getDefault().register(this); // 注册成为订阅者,成为了订阅者就可以接收消息
  6. AnimationDrawable rocketAnimation = (AnimationDrawable) ivVisualEffect.getBackground();
  7. rocketAnimation.start(); // 开启帧动画
  8. }
 获取消息 
  1. public class AudioPlayerActivity extends BaseActivity {
  2.  ............
  3. @Subscribe
  4. public void onReceivePlayServic(PlayService playService) {
  5. this.playService = playService;
  6. EventBus.getDefault().post(this);
  7. }
  8. ............. 
  9. }
销毁
  1. @Override
  2. protected void onDestroy() {
  3. super.onDestroy();
  4. EventBus.getDefault().unregister(this);
  5. handler.removeCallbacksAndMessages(null);
  6. }


EventBus 有4种模型  PostThread(默认)、MainThread、BackgroundThread与Async

             PostThread:如果使用事件处理函数指定了线程模型为PostThread,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为PostThread的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
            
              MainThread:如果使用事件处理函数指定了线程模型为MainThread,那么不论事件是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。该方法可以用来更新UI,但是不能处理耗时操作。
          
              BackgroundThread:如果使用事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
             
              Async:如果使用事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。同样,此事件处理函数中禁止进行UI更新操作。

   一般默认就可以  4中用法的小例子
  1. @Subscribe(threadMode = ThreadMode.PostThread)
  2. public void onMessageEventPostThread(MessageEvent messageEvent) {
  3. Log.e("PostThread", Thread.currentThread().getName());
  4. }
  5. @Subscribe(threadMode = ThreadMode.MainThread)
  6. public void onMessageEventMainThread(MessageEvent messageEvent) {
  7. Log.e("MainThread", Thread.currentThread().getName());
  8. }
  9. @Subscribe(threadMode = ThreadMode.BackgroundThread)
  10. public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
  11. Log.e("BackgroundThread", Thread.currentThread().getName());
  12. }
  13. @Subscribe(threadMode = ThreadMode.Async)
  14. public void onMessageEventAsync(MessageEvent messageEvent) {
  15. Log.e("Async", Thread.currentThread().getName());
  16. }
              分别使用上面四个方法订阅同一事件,打印他们运行所在的线程。首先我们在UI线程中发布一条MessageEvent的消息,看下日志打印结果是什么。
  1. findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. Log.e("postEvent", Thread.currentThread().getName());
  5. EventBus.getDefault().post(new MessageEvent());
  6. }
  7. });
  1. 打印结果如下:
  2. 2689-2689/com.lling.eventbusdemo E/postEvent main
  3. 2689-2689/com.lling.eventbusdemo E/PostThread main
  4. 2689-3064/com.lling.eventbusdemo E/Async pool-1-thread-1
  5. 2689-2689/com.lling.eventbusdemo E/MainThread main
  6. 2689-3065/com.lling.eventbusdemo E/BackgroundThread pool-1-thread-2

从日志打印结果可以看出,如果在UI线程中发布事件,则线程模型为PostThread的事件处理函数也执行在UI线程,与发布事件的线程一致。线程模型为Async的事件处理函数执行在名字叫做pool-1-thread-1的新的线程中。而MainThread的事件处理函数执行在UI线程,BackgroundThread的时间处理函数执行在名字叫做pool-1-thread-2的新的线程中。

我们再看看在子线程中发布一条MessageEvent的消息时,会有什么样的结果

  1. findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. Log.e("postEvent", Thread.currentThread().getName());
  8. EventBus.getDefault().post(new MessageEvent());
  9. }
  10. }).start();
  11. }
  12. });
  1. 打印结果如下:
  2. 3468-3945/com.lling.eventbusdemo E/postEvent Thread-125
  3. 3468-3945/com.lling.eventbusdemo E/PostThread Thread-125
  4. 3468-3945/com.lling.eventbusdemo E/BackgroundThread Thread-125
  5. 3468-3946/com.lling.eventbusdemo E/Async pool-1-thread-1
  6. 3468-3468/com.lling.eventbusdemo E/MainThread main

从日志打印结果可以看出,如果在子线程中发布事件,则线程模型为PostThread的事件处理函数也执行在子线程,与发布事件的线程一致(都是Thread-125)。BackgroundThread事件模型也与发布事件在同一线程执行。Async则在一个名叫pool-1-thread-1的新线程中执行。MainThread还是在UI线程中执行。

上面一个例子充分验证了指定不同线程模型的事件处理方法执行所在的线程。

~~~~~~~~~~~~~~~~~~~~ 
看不懂  以后再说     

,EventBus还支持发送黏性事件。何为黏性事件呢?简单讲,就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。具体用法如下
订阅黏性事件:
  1. EventBus.getDefault().register(StickyModeActivity.this);
黏性事件处理函数:
  1. @Subscribe(sticky = true)
  2. public void XXX(MessageEvent messageEvent) {
  3. ......
  4. }
发送黏性事件:
  1. EventBus.getDefault().postSticky(new MessageEvent("test"));

处理消息事件以及取消订阅和上面方式相同。

看个简单的黏性事件的例子,为了简单起见我这里就在一个Activity里演示了。

Activity代码:

  1. public class StickyModeActivity extends AppCompatActivity {
  2. int index = 0;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_sticky_mode);
  7. findViewById(R.id.post).setOnClickListener(new View.OnClickListener() {
  8. @Override
  9. public void onClick(View v) {
  10. EventBus.getDefault().postSticky(new MessageEvent("test" + index++));
  11. }
  12. });
  13. findViewById(R.id.regist).setOnClickListener(new View.OnClickListener() {
  14. @Override
  15. public void onClick(View v) {
  16. EventBus.getDefault().registerSticky(StickyModeActivity.this);
  17. }
  18. });
  19. findViewById(R.id.unregist).setOnClickListener(new View.OnClickListener() {
  20. @Override
  21. public void onClick(View v) {
  22. EventBus.getDefault().unregister(StickyModeActivity.this);
  23. }
  24. });
  25. }
  26. @Subscribe(threadMode = ThreadMode.PostThread, sticky = true)
  27. public void onMessageEventPostThread(MessageEvent messageEvent) {
  28. Log.e("PostThread", messageEvent.getMessage());
  29. }
  30. @Subscribe(threadMode = ThreadMode.MainThread, sticky = true)
  31. public void onMessageEventMainThread(MessageEvent messageEvent) {
  32. Log.e("MainThread", messageEvent.getMessage());
  33. }
  34. @Subscribe(threadMode = ThreadMode.BackgroundThread, sticky = true)
  35. public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
  36. Log.e("BackgroundThread", messageEvent.getMessage());
  37. }
  38. @Subscribe(threadMode = ThreadMode.Async, sticky = true)
  39. public void onMessageEventAsync(MessageEvent messageEvent) {
  40. Log.e("Async", messageEvent.getMessage());
  41. }
  42. }
布局代码activity_sticky_mode.xml:
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:orientation="vertical"
  5. tools:context="com.lling.eventbusdemo.StickyModeActivity">
  6. <Button
  7. android:id="@+id/post"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:text="Post"/>
  11. <Button
  12. android:id="@+id/regist"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:text="Regist"/>
  16. <Button
  17. android:id="@+id/unregist"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:text="UnRegist"/>
  21. </LinearLayout>
代码很简单,界面上三个按钮,一个用来发送黏性事件,一个用来订阅事件,还有一个用来取消订阅的。首先在未订阅的情况下点击发送按钮发送一个黏性事件,然后点击订阅,会看到日志打印结果如下:
  1. 15246-15246/com.lling.eventbusdemo E/PostThread﹕ test0
  2. 15246-15391/com.lling.eventbusdemo E/Async﹕ test0
  3. 15246-15246/com.lling.eventbusdemo E/MainThread﹕ test0
  4. 15246-15393/com.lling.eventbusdemo E/BackgroundThread﹕ test0
这就是粘性事件,能够收到订阅之前发送的消息。但是它只能收到最新的一次消息,比如说在未订阅之前已经发送了多条黏性消息了,然后再订阅只能收到最近的一条消息。这个我们可以验证一下,我们连续点击5次POST按钮发送5条黏性事件,然后再点击REGIST按钮订阅,打印结果如下:

  1. 6980-6980/com.lling.eventbusdemo E/PostThread﹕ test4
  2. 6980-6980/com.lling.eventbusdemo E/MainThread﹕ test4
  3. 6980-7049/com.lling.eventbusdemo E/Async﹕ test4
  4. 6980-7048/com.lling.eventbusdemo E/BackgroundThread﹕ test4
由打印结果可以看出,确实是只收到最近的一条黏性事件。

Demo https://github.com/liuling07/EventBusDemo

原文链接:http://www.jianshu.com/p/da9e193e8b03









0 0
原创粉丝点击