是否可以仅通过Android中的单个top activity来处理Event Bus的事件?

Is it possible to process Event Bus's events only by a single top activity in Android?

当我们使用事件总线(来自 Guava)从服务器获取异步响应时 - 一切正常。但是,如果我们想在顶部打开相同 activity 的另一个实例,那么我们的订阅事件也将在底部处理(已停止)activity 导致不同来源的错误。

是否可以使事件总线的事件仅由当前顶部的单个订阅者处理activity?

有两种解决方法:

  1. 您订阅的地点和订阅前的活动请先取消订阅,然后再订阅。之后将在 eventbus 事件堆栈中一次只执行一个订阅。
  2. 我认为您有一个 BaseActivity,每当您创建一个时,事件总线订阅就会在每个 activity 上发生。为此,您可以在onresume中订阅,在onpause中取消订阅将解决您的问题。

当你在 activity re-creates 之前使用以下方法删除所有粘性事件:-

stickyEvent= EventBus.getDefault().getStickyEvent(classType);
// Better check that an event was actually posted before
        if(stickyEvent != null) {
            // "Consume" the sticky event
            EventBus.getDefault().removeStickyEvent(stickyEvent);
        }

对于那些曾经利用事件总线范式来获取异步操作结果的人(并保持 activity 或片段的方向更改事件和正确的工作,即使我们当前打开了多个相同的活动),我建议以下样板实现。它基于Greenrobot的事件总线库,当然在这里使用任何其他库也不难。

首先,让我们创建一种助手class来为事件总线发送事件:

/**
 * Helps to send sticky events avoiding them to be sent when the current screen (content entity)
 * is about to be closed.
 */
public enum EventBusHelper {

/** Single instance. */
INSTANCE;

/**
 * Posts sticky event to make activity fetch it (if activity is not finishing).
 *
 * @param activity An activity to check state.
 * @param event    An event to be fired.
 * */
public void postStickyIfNotFinishing(@NonNull Activity activity, Object event) {
    postStickyIfNotFinishing(activity.isFinishing(), event);
}

/**
 * Posts sticky event to make fragment fetch it (if fragment is not finishing).
 *
 * @param fragment A fragment to check state.
 * @param event    An event to be fired.
 * */
public void postStickyIfNotFinishing(@NonNull Fragment fragment, Object event) {
    postStickyIfNotFinishing(fragment.isRemoving(), event);
}

/**
 * Posts sticky event if a subscriber is not going to be finished.
 *
 * @param isFinishing True - if subscriber will be finished.
 * @param event An event to be sent.
 * */
private void postStickyIfNotFinishing(boolean isFinishing, Object event) {
    if (!isFinishing)
        EventBus.getDefault().postSticky(event);
}

此 class 的主要目的是仅当我们的 activity、片段(对话片段)不会关闭时才发送 Subscribe-methods 的事件。否则,当我们在 activity(片段等)的下一次启动时获取一些即时数据而没有首先触发我们的请求时,我们将得到不可接受的行为。但是当我们的屏幕实体(activity,片段)在屏幕方向改变后即将被重新创建时,这种事件发送方法不会阻止事件的发送。

下一步 - 是在我们的 activity 或片段:

的启动和停止操作上注册和注销事件总线
/**
 * Initializing event bus to process completed tasks.
 * */
@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

/**
 * Stopping event bus to avoid background ops processing.
 * */
@Override
public void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}

有两个必要:

  1. 为了避免任何后台操作,当我们收到后台任务的回调时。
  2. 避免在多个屏幕实体(活动等)同时打开时处理我们的回调(一个 activity 在另一个之上)。它有效,因为当前只有一个屏幕实体在我们的屏幕上处于活动状态(另一个处于停止状态)。

最后一步。当我们想要 post 我们的片段中的某个事件或 activity (例如,在从异步服务器请求获得响应之后),我们应该使用我们的助手 class 中的 post 方法:

ExampleAsyncRequest exampleAsyncRequest = new ExampleAsyncRequest(
            new Response.Listener<ExampleAsyncRequestResponse>() {
                @Override
                public void onResponse(ExampleAsyncRequestResponse response) {
                    EventBusHelper.INSTANCE.postStickyIfNotFinishing(OurFragment.this, response);
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(ExampleAsyncRequestError error) {
                    EventBusHelper.INSTANCE.postStickyIfNotFinishing(OurFragment.this, error);
                }
    });

为了在我们的总线中获取这些事件,我们使用下一个代码:

@Subscribe(sticky = true)
public void onExampleAsyncRequestResponse(ExampleAsyncRequestResponse response) {
    EventBus.getDefault().removeStickyEvent(response);
    ...
}

@Subscribe(sticky = true)
public void onExampleAsyncRequestError(ExampleAsyncRequestError error) {
    EventBus.getDefault().removeStickyEvent(error);
    ...
}

我们必须删除获得的粘性事件,以避免它们被另一个 activity 或当前位于顶部的片段处理。