片段实例中带有 Otto 事件总线的 IllegalArgumentException
Posted
技术标签:
【中文标题】片段实例中带有 Otto 事件总线的 IllegalArgumentException【英文标题】:IllegalArgumentException with Otto Event bus in Fragment instance 【发布时间】:2013-11-10 15:27:14 【问题描述】:我正在使用 Otto 事件总线订阅 ListFragment 中的某些事件。总线实例是在 Application 的子类中存储和创建的,换句话说,它总线应该作为一个单例工作。好像不是这样的……
片段在onActivityCreated(Bundle)
中注册到总线并在onDestroy()
中取消注册。这不能正常工作。我从调用unregister()
(java.lang.IllegalArgumentException: Missing event handler for an annotated method...) 时应用程序崩溃的设备收到了几份崩溃报告。只有在调用任何 register() 之前调用 unregister()
或调用两次 unregister()
时才会引发此异常。这可能只发生在......
onActivityCreated(Bundle)
不会在 onDestroy()
之前调用。
onDestroy()
被调用了两次。
Application
实例在调用 onActivityCreated(Bundle)
和 onDestroy()
之间重新创建。
我的应用类:
public class App extends Application
private static App sInstance;
private Bus bus;
public static App getInstance()
return sInstance;
@Override
public void onCreate()
super.onCreate();
sInstance = this;
bus = new Bus(ThreadEnforcer.ANY);
public Bus getEventBus()
return bus;
片段类:
public class MyFragment extends ListFragment
@Override
public void onActivityCreated(Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
App.getInstance().getEventBus().register(this);
@Subscribe
public void onEvent(MyEvent event)
....
@Override
public void onDestroy()
App.getInstance().getEventBus().unregister(this);
super.onDestroy();
更新:
我遗漏了一个重要的细节;这些片段用于ViewPager
。当用户在ViewPager
中的页面之间滑动时,它们会按需实例化。这个小细节似乎改变了某些设备上的片段生命周期:onActivityCreated()
在创建ViewPager
之后启动的片段永远不会被调用。
【问题讨论】:
为什么不在onCreate() / onDestroy()
中调用它?他们配对了。
【参考方案1】:
我有同样的问题。在某些情况下,实例保持在总线上注册。一个可靠的解决方案是使用onStart()
/onStop()
方法来注册/注销接收器。这也是 Square 的人建议的。他们是这样解释的。如果活动在后台,则无论如何都不需要刷新 UI,因为 UI 是不可见的。一旦 Activity 进入前台,它将接收更新并刷新 UI。
更新: 如 cmets 中所述,在 onResume()
/onPause()
中注册/取消注册在某些情况下可能会导致一些不良影响,例如如果您的活动上显示一个对话框,然后活动被暂停并且无法再接收事件。
【讨论】:
问题是:如果片段正在等待后台任务会发生什么,就像从服务器获取项目列表一样。如果用户在绘制列表之前离开了 Fragment,您将永远无法获得项目,因为 Fragment 已取消注册总线,对吧? 我正在使用它。我习惯于在 onActivityCreated 中注册总线并在我的片段中的 onDestroy 方法中取消注册它。试图提高gpu性能,而不是向内容添加片段(我没有任何问题)我替换片段,所以当我弹出最后一个替换的片段时出现总线问题,因为它没有通过onDestroy方法可以你明白我的意思吗? 是的,谢谢。我认为适合我的情况的最佳选择是在 onActivityCreated/onDestroyView 方法中注册/取消注册,因为返回堆栈^_^ 除特殊用途外,请勿在register()
/unregister()
Otto 期间使用片段。我发现了一个漏洞。如果在应该接收总线事件的片段上显示一个对话框,片段上的 onPause()
将被调用并意外取消注册 Otto。
@ThuyTrinh 这不是onPause
的明确目的吗?以上是关于片段实例中带有 Otto 事件总线的 IllegalArgumentException的主要内容,如果未能解决你的问题,请参考以下文章