天天看點

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