天天看点

Android EventBus Sticky Events粘性事件详解

简介

普通事件:通过post()方法发出的普通事件,会被已经注册的订阅者接收到,若订阅者是在消息发送之后才注册,那么是不会接收到该事件的

粘性事件:而粘性事件是可以被事件发出之后才注册的订阅者接收到,也可以在事件发出之后通过主动查询获取事件内容。粘性事件实现原理其实是把最近的事件缓存到内存中,之后注册的订阅者还可以查询出来

比如在AActivity中发送一个粘性事件Event,然后打开BActivity,在BActivity中注册Event的粘性事件订阅者,在注册后马上可以接收到该事件。而如果是普通事件的话是接收不到的,因为订阅者是在消息发送之后才注册的。这就是粘性事件的方便之处。

发送粘性事件

先定义一个事件类型

public class MessageEvent {
    public String message;
    public MessageEvent(String message) {
        this.message = message;
    }
}
           

发送粘性事件 

EventBus.getDefault().postSticky(new MessageEvent("野猿新一"));
           

订阅粘性事件

// 订阅
@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
 
// 接收粘性事件的方法
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
    Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show(); 
}
 
// 取消订阅
@Override
public void onStop() {
    EventBus.getDefault().unregister(this);    
    super.onStop();
}
           

主动获取及移除粘性事件

粘性事件除了可以通过订阅获取外,还可以通过getStickyEvent()方法主动获取

MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
           

还可以通过removeStickyEvent()方法移除粘性事件,表示消费了该事件,避免后面重新订阅还会再重复收到该事件

if(stickyEvent != null) {
    // "Consume" the sticky event
    EventBus.getDefault().removeStickyEvent(stickyEvent);
    // Now do something with it
}
           

removeStickyEvent方法还有一个重载方法,出入的参数是类而不是对象,该方法会移除该类型最近的粘性事件,并返回该事件。所以以上获取粘性事件并移除的代码还可以简化如下

MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
    // Now do something with it
}
           

测试

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new MessageEvent("普通事件"));
            }
        });
        findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().postSticky(new MessageEvent("粘性事件"));
            }
        });
    }

    public static class MessageEvent {
        public String message;
        public MessageEvent(String message) {
            this.message = message;
        }
    }

    // 订阅
    @Override
    public void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    // 接收粘性事件的方法
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onNormalEvent(MessageEvent event) {
        Log.d("StickyEvents", "onNormalEvent:" + event.message);
        Toast.makeText(this, "onNormalEvent:" + event.message, Toast.LENGTH_SHORT).show();
    }

    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    public void onStickyEvent(MessageEvent event) {
        Log.d("StickyEvents", "onStickyEvent:" + event.message);
        Toast.makeText(this, "onStickyEvent:" +event.message, Toast.LENGTH_SHORT).show();
    }

    // 取消订阅
    @Override
    public void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }
}
           
2019-12-27 14:22:10.091 24825-24825/com.him.hisapp D/StickyEvents: onNormalEvent:普通事件
2019-12-27 14:22:10.101 24825-24825/com.him.hisapp D/StickyEvents: onStickyEvent:普通事件
2019-12-27 14:22:11.574 24825-24825/com.him.hisapp D/StickyEvents: onNormalEvent:粘性事件
2019-12-27 14:22:11.588 24825-24825/com.him.hisapp D/StickyEvents: onStickyEvent:粘性事件
           

从以上测试代码及打印的日志可知:

若粘性事件订阅者在普通事件发送前注册,也是可以收到到普通事件的

若普通事件订阅者在粘性事件发送前注册,也是可以接收到粘性事件的

参考

Sticky Events