4

MainActivity has a NavigationDrawer and each navigation menu brings Fragment instead of new Activity.

There is settings fragment and if I change order of the navigation menu it should be reflected immediately to NavigationDrawerFragment.

I post event in SettingsFragment, however it did not appear on NavigationDrawerFragment.

I made a AndroidBus extends Bus

public class AndroidBus extends Bus {

    private final Handler mainThread = new Handler(Looper.getMainLooper());

    public AndroidBus() {
        super(ThreadEnforcer.ANY);
    }

    @Override
    public void post(final Object event) {
        if (BuildConfig.DEBUG) Ln.d("BUS: SYNC current thread="+Thread.currentThread().getName()+", post=" + event + " bus=" + this);
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            mainThread.post(new Runnable() {
                @Override
                public void run() {
                    post(event);
                }
            });
        }
    }

    @Override
    public void register(Object object) {
        super.register(object);
        if (BuildConfig.DEBUG) Ln.d("BUS: SYNC current thread="+Thread.currentThread().getName()+", register=" + object + " bus=" + this);
    }

    @Override
    public void unregister(Object object) {
        super.unregister(object);
        if (BuildConfig.DEBUG) Ln.d("BUS: SYNC current thread="+Thread.currentThread().getName()+", unregister=" + object + " bus=" + this);
    }
}

and I inject bus object to each fragment by Dagger and I register fragment in onActivityCreated, and unregister it onDestroyView.

If I post event it is not delivered and I see DeadEvent log.

08-07 11:00:27.203    3519-3519/com.test.app.debug D//AndroidBus.java:40﹕ main BUS: SYNC current thread=main, register=com.test.app.ui.MainActivity@536fa3b0 bus=[Bus "default"]

08-07 11:00:27.231    3519-3519/com.test.app.debug D//AndroidBus.java:40﹕ main BUS: SYNC current thread=main, register=NavigationDrawerFragment{536b79a4 #0 id=0x7f0a0072} bus=[Bus "default"]

08-07 11:00:27.247    3519-3519/com.test.app.debug D//MainActivity.java:127﹕ main SYNC: register: bus=[Bus "default"]
08-07 11:00:27.251    3519-3519/com.test.app.debug D//AndroidBus.java:40﹕ main BUS: SYNC current thread=main, register=SettingsFragment{536b7a2c #1 id=0x7f0a0071} bus=[Bus "default"]


08-07 11:00:31.415    3519-3519/com.test.app.debug D//AndroidBus.java:24﹕ main BUS: SYNC current thread=main, post=com.test.app.events.SettingsUpdatedEvent@536d1aa4 bus=[Bus "default"]
08-07 11:00:31.415    3519-3519/com.test.app.debug D//AndroidBus.java:24﹕ main BUS: SYNC current thread=main, post=com.squareup.otto.DeadEvent@5352027c bus=[Bus "default"]

I register MainActivity also in onCreate method, if I subscribe same event in MainActivity it receives the event.

Thank you for reading this and I hope someone enlighten me about this.

Chk0nDanger
  • 1,211
  • 1
  • 10
  • 26

3 Answers3

12

I revisited this problem, and found my stupidity. The reason is that I used different @Subscribe annotation. It could happen when you use both Otto and Guava libraries. Therefore, beware of this when you use both libraries in your Android app.

-import com.google.common.eventbus.Subscribe;
+import com.squareup.otto.Subscribe;
Chk0nDanger
  • 1,211
  • 1
  • 10
  • 26
2

I'd also like to add to the conversation that you CANNOT declare @Subscribe methods in an interface or super class, they will not be called.

From the Otto docs:

Registering will only find methods on the immediate class type. Unlike the Guava event bus, Otto will not traverse the class hierarchy and add methods from base classes or interfaces that are annotated. This is an explicit design decision to improve performance of the library as well as keep your code simple and unambiguous.

EventBus by greenrobot supports this feature: https://github.com/greenrobot/EventBus

Sakiboy
  • 7,252
  • 7
  • 52
  • 69
1

AFAIK, your second fragment doesn't receive event message because it is created too late while the first fragment post event before second fragment's onActivityCreated is called.
To solve this, you should keep the event object in memory until the second fragment is created and can receive this event. I am not sure that Otto Bus can support this function. The second option is keeping your event object in activity class and the second fragment get it by call getActivity(), but this way will break EventBus meaning.
So I recommend the last one: using GreenRobot EventBus , it supports more features than Otto, for example: post on main thread and background thread, cache events (sticky event). Your problem will be done by using Sticky event with GreenRobot EventBus:

   // Register stictky subscribers on onResume()
   EventBus.getDefault().registerSticky(this);

   // Unregister subscriber on onPause()
   EventBus.getDefault().unregister(this);

   // your subscribe event here 
   public void onEvent(AnyEventType event) {

   }

   // or subscribe event on main thread 
   public void onEventMainThread(AnyEventType event) {

   }

   // Post sticky events from the first fragment to the bus:
   EventBus.getDefault().postSticky(AnyEventType);

Update: maybe I am wrong about your problem, there was the same problem and is resolved by remove ThreadEnforcer.ANY, you can try it.

Community
  • 1
  • 1
ductran
  • 10,043
  • 19
  • 82
  • 165
  • thank you for the answer, however, first one, both fragments are created before posting event. second I post event in main thread, the log I posted is confirm both. So changing ThreadEnforcer.ANY is no help. If I try GreenRobot EventBus and it is resolve this, I will move to it. Thank you for suggesting that. – Chk0nDanger Aug 07 '14 at 03:41
  • 1
    `GreenRobot's EventBus` resolves this issue, I think it should happen in `Otto`. but... I really have no idea why this does not work with Otto. I even no need sticky event in `GreenRobot's EventBus` to do this. I just use as same code as with `Otto`, same registering code below in `Otto`'s registering code and same posting code below `Otto`'s registering code with same `Event`. – Chk0nDanger Aug 07 '14 at 06:52
  • I found a strange one on your post method: why do you use recursive on this: `post(event);`? According this answer http://stackoverflow.com/a/15433353/719212 , your approach maybe wrong – ductran Aug 07 '14 at 07:05
  • Or you can use `AndroidBus.super.post(event);` for that – ductran Aug 07 '14 at 07:08
  • Thank you, I changed it to use super.post however it still not work. I am going to use GreenRebot's EventBus. – Chk0nDanger Aug 07 '14 at 08:47