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.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.
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.