片段实例中带有 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的主要内容,如果未能解决你的问题,请参考以下文章

java 示例Otto事件总线提供程序

其他进程可以看到总线事件吗?

Android Otto框架浅析

android事件总线(eventbus)设计与实现

RuntimeException:无法调度事件@otto

事件总线模式——实例讲解