Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IllegalArgumentException with Otto Event bus in Fragment instance

I am using Otto Event bus to subscribe to certain events in a ListFragment. The bus instance is stored and created in an subclass of Application, in other words, it bus should work as a singleton. It seems like this is not a case...

The fragment is registering to the bus in onActivityCreated(Bundle) and unregistering in onDestroy(). This does not work as it should. I have gotten several crash reports from devices where the app crashes when calling unregister() (java.lang.IllegalArgumentException: Missing event handler for an annotated method...). This exception is only thrown if unregister() is called before any call to register(), or if unregister() is called twice. This may only happen if...

  • onActivityCreated(Bundle) is not called before onDestroy().
  • onDestroy() is called twice.
  • The Application instance is recreated between between the call to onActivityCreated(Bundle) and onDestroy().

My application class:

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;
    }

}

The Fragment class:

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();
    }
}

UPDATE:

I left out an important detail; the fragments were used in a ViewPager. They are instantiated on demand as the users slides between the pages in the ViewPager. This minor detail seems alter the fragments life-cycle on some devices: onActivityCreated() is never called for fragments initiated after the ViewPager is created.

like image 680
bjorncs Avatar asked Oct 30 '13 19:10

bjorncs


1 Answers

I had same issue. Instance stayed registered in the bus in some cases. A reliable solution is to use onStart()/onStop() methods to register/unregister receivers. This is what Square guys suggest too. They explain it like this. If activity is in background, it does not need to refresh UI anyway, because UI is not visible. Once activity comes foreground, it will receive update and refresh UI.

Update: as mentioned in the comments, registering / unregistering in onResume()/onPause() can cause some undesired effects in certain cases like if there is a dialog shown over your activity, then activity gets paused and is not able to receive events anymore.

like image 142
sergej shafarenka Avatar answered Nov 07 '22 06:11

sergej shafarenka