在使用EventBus时,我遇到了意外情况,即片段取消注册后,片段的订阅方法也会被调用一次。
情景是这样的。我有一个Activity,其中包含可以放置任何Fragment的布局。活动以某个片段开头。
活动和片段在onResume()
上注册,并在onPause()
上取消注册。对于同一类型的事件,他们都有自己的处理程序。
通过调度事件,Activity会根据某种情况将Fragment替换为另一个。然后,在删除过程中调用片段onPause()
,同时执行EventBus.getDefault().unregister(this)
。
然后,我希望现在不会调用Fragment的处理程序。但是在片段未注册后立即调用它。
似乎EventBus没有处理任何订阅者在事件发布过程中未注册的情况。有谁知道这个问题?
编辑了更多详情
片段中的相关方法
@Override
public void onResume() {
Log.d(LOG_TAG, "onResume()");
super.onResume();
EventBus.getDefault().register(this);
Communicator.registerListener(listener);
}
@Override
public void onPause() {
Log.d(LOG_TAG, "onPause()");
Communicator.unregisterListener(listener);
EventBus.getDefault().unregister(this);
super.onPause();
}
@Subscribe(sticky = true)
public void handleEvent(DeviceConnectionSelectEvent event) {
if (event.container != null) {
setDevice(event.container.getRapaelDevice());
}
}
调用onPause()
Fragment.onPause()
at com.neofect.rapael.client.bridge.app.device.kids.SmartKidsSensorDataFragment.onPause(SmartKidsSensorDataFragment.java:105)
at android.support.v4.app.Fragment.performPause(Fragment.java:2139)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1117)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234)
at android.support.v4.app.FragmentManagerImpl.dispatchPause(FragmentManager.java:2060)
at android.support.v4.app.Fragment.performPause(Fragment.java:2135)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1117)
at android.support.v4.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1349)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:695)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
at com.neofect.rapael.client.bridge.app.MainActivity.changeDeviceDetailFragment(MainActivity.java:111)
at com.neofect.rapael.client.bridge.app.MainActivity.handleEvent(MainActivity.java:100)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at org.greenrobot.eventbus.EventBus.invokeSubscriber(EventBus.java:485)
at org.greenrobot.eventbus.EventBus.postToSubscription(EventBus.java:416)
at org.greenrobot.eventbus.EventBus.postSingleEventForEventType(EventBus.java:397)
at org.greenrobot.eventbus.EventBus.postSingleEvent(EventBus.java:370)
at org.greenrobot.eventbus.EventBus.post(EventBus.java:251)
at org.greenrobot.eventbus.EventBus.postSticky(EventBus.java:292)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter.selectConnectionItem(DeviceConnectionListPresenter.java:114)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter.access$400(DeviceConnectionListPresenter.java:28)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter$1.onDeviceReady(DeviceConnectionListPresenter.java:179)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter$1.onDeviceReady(DeviceConnectionListPresenter.java:122)
at com.neofect.communicator.CommunicationHandler$5.run(CommunicationHandler.java:90)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
调用handleEvent()
堆栈 - 在onPause()
Fragment.handleEvent()
at com.neofect.rapael.client.bridge.app.device.kids.SmartKidsSensorDataFragment.handleEvent(SmartKidsSensorDataFragment.java:121)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at org.greenrobot.eventbus.EventBus.invokeSubscriber(EventBus.java:485)
at org.greenrobot.eventbus.EventBus.postToSubscription(EventBus.java:416)
at org.greenrobot.eventbus.EventBus.postSingleEventForEventType(EventBus.java:397)
at org.greenrobot.eventbus.EventBus.postSingleEvent(EventBus.java:370)
at org.greenrobot.eventbus.EventBus.post(EventBus.java:251)
at org.greenrobot.eventbus.EventBus.postSticky(EventBus.java:292)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter.selectConnectionItem(DeviceConnectionListPresenter.java:114)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter.access$400(DeviceConnectionListPresenter.java:28)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter$1.onDeviceReady(DeviceConnectionListPresenter.java:179)
at com.neofect.rapael.client.bridge.app.ui.device_connection_list.DeviceConnectionListPresenter$1.onDeviceReady(DeviceConnectionListPresenter.java:122)
at com.neofect.communicator.CommunicationHandler$5.run(CommunicationHandler.java:90)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
根据上述内容,handleEvent()
在与onPause()
相同的调用堆栈上调用。它们在一个事件发布中被调用。
我猜测事件调度循环(消息队列循环)在开始发布之前保留了订阅列表,因此它无法处理在发布过程中完成的订阅删除。
答案 0 :(得分:2)
你是对的。
如果查看事件总线的源代码,您将看到相同的线程(在您的情况下为MAIN)如果订阅在发布过程中处于活动状态,则事件总线不会重新检查:
在此方法中,事件总线到达postSingleEventForEventType()
,此时它将获取所有可用的订阅并通知它们。那些来自同一个线程的,没有检查执行:
EventBus#invokeSubscriber(subscription, event)
其他人已安排,并将使用执行检查的方法执行:
EventBus#invokeSubscriber(pendingPost)
在此方法中,事件总线到达unsubscribeByEventType()
,获取相同的订阅,删除和停用相应的订阅:
List<Subscription> subscriptions = subscriptionsByEventType.get(eventClass);
for (...) {
// ...
subscription.active = false;
subscriptions.remove(i);
}