How to recognize Otto's subscriber
I am using Otto by area. My subscriber class is registered in Activity / Fragment onStart
and onStop
.
However, sometimes I get this error
Thrown: java.lang.IllegalArgumentException: Missing event handler for annotated method. Is the EventListener class registered? at com.squareup.otto.Bus.unregister (Bus.java:289)
I'm sure my class is registered. Is there a way to find out if this class is registered or not?
// in a Fragment or Activity
@Override
public void onStart() {
super.onStart();
Bus bus = new Bus();
bus.register(eventListener); // register the class where the annotated @Subscribe method is
bus.isRegistered(); // ??
}
source to share
Like @laalto, there is no such method in the Bus API. This is how I implemented the boolean isRegistered
// implement as a Singleton class
public class EventListener {
// necessary to avoid to unregister a non-registered instance . Since EventListener is a Singleton
private static boolean isRegistered;
public void setIsRegistered(final boolean registered){
isRegistered = registered;
}
public boolean isRegistered(){
return isRegistered;
}
@Subscribe
public void onTrackingEvent(final TrackingEvent event) {
// to do
}
}
Now in a Snippet or Activity, register / unregister for com.squareup.otto.Bus
// in a Fragment or Activity
@Override
public void onStart() {
super.onStart();
// eventListener is the class containing the @Subscribe method
bus.register(eventListener);
eventListener.setIsRegistered(true);
}
@Override
public void onStop() {
super.onStop();
if (eventListener.isRegistered()) {
bus.unregister(eventListener);
eventListener.setIsRegistered(false);
}
}
source to share
You receive this error message if you try unregister()
an object that has not been registered or is not registered twice.
Since registration is object-based, you can simply add a member boolean isRegistered
to those classes where the normal lifecycle does not guarantee correct register / non-regression pairing.
source to share
as explained above, the Otto API does not provide a way to poll if a potential subscriber has registered with an instance Bus
. the failing semantics are meant to cause your code to have an unpaired call register()
and / or unregister()
, rather than letting that condition linger further and introduce some potentially unexpected side effects later.
While I agree with the approach, I recently found that I had little time to track down this issue in one of my own projects, so I implemented a quick and dirty little Kotlin-based hack using extension features to give myself a break. The below swallows IllegalArgumentExceptions
related to duplicate registrations as well as attempts to deregister subscribers who are not yet registered. it is quite fragile and it would be more efficient to avoid handling exceptions all together, but it takes at least less scaffolding to maintain a component's registration state:
fun Bus.registerSafely(`object`: Any) {
try {
this.register(`object`)
} catch(t: Throwable) {
when(t) {
is IllegalArgumentException -> {
val message = t.message
if(message != null && message.contains("Object already registered", ignoreCase = true)) {
/* quietly ignore this... */
} else {
throw t
}
}
else -> throw t
}
}
}
fun Bus.unregisterSafely(`object`: Any) {
try {
this.unregister(`object`)
} catch(t: Throwable) {
when(t) {
is IllegalArgumentException -> {
val message = t.message
if(message != null && message.contains("Missing event handler", ignoreCase = true)) {
/* quietly ignore this... */
} else {
throw t
}
}
else -> throw t
}
}
}
source to share