2

I am working on an app which uses the NavigationDrawer. Different fragments are placed into the content view of the MainActivity whenever a menu item in the drawer is selected. To inform the MainActivity that a Fragment successfully attached the following callback is executed:

public class CustomFragment extends Fragment {

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        ((MainActivity) activity).onSectionAttached();
    }

}

Since I am started using Otto with Dagger in the project I am curious how I can substitute the callback with a .post() event such as:

mBus.post(new CustomFragmentAttachedEvent);

The problem is that mBus is null in onAttach(). It gets initialized in onCreate().

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ((MyApp) getActivity().getApplication()).getObjectGraph().inject(this);
}

Here is an example of such a Fragment class.

References:


You can easily try out the example yourself: Create a new project from the NavigationDrawer template available in Android Studio, add Dagger and Otto and try to substitute the mentioned callback.


Working solution:

JJD
  • 50,076
  • 60
  • 203
  • 339
  • I can't help, but I am just wondering why you can't create the reference to mBus in the activity onCreate or in the onInflate of the fragment. Again, just curious. – nPn May 20 '14 at 16:56
  • 1
    @nPn I am just following [what Jake Wharton told (slide 141)](https://speakerdeck.com/jakewharton/android-apps-with-dagger): inject in `onCreate()`. – JJD May 21 '14 at 08:35

1 Answers1

2

You can create a provider for your Otto bus with Dagger as follows:

@Module(injects = {
    YourFragment.class, 
    MainActivity.class
},complete = true)    
public class EventBusModule {

    @Provides
    @Singleton
    Bus provideBus() {
        return new Bus();
    }
}

Then you register the EventBusModule when you create your ObjectGraph. You can create your graph in the Application's onCreate():

public class MyApplication extends Application{

    public void onCreate() {
        Object[] modules = new Object[]{new EventBusModule()};
        Injector.init(modules);
    }

}

You would need to create an Injector that has some static methods and a reference to the ObjectGraph so you can manipulate it without having a reference to the Application. Something like this:

public final class Injector {

    private static ObjectGraph objectGraph = null;

    public static void init(final Object... modules) {

        if (objectGraph == null) {
            objectGraph = ObjectGraph.create(modules);
        }
        else {
            objectGraph = objectGraph.plus(modules);
        }

        // Inject statics
        objectGraph.injectStatics();
    }

    public static final void inject(final Object target) {
        objectGraph.inject(target);
    }

    public static <T> T resolve(Class<T> type) {
        return objectGraph.get(type);
    }
}

Then you just use @Inject in your Fragment to let Dagger give you a Bus instance and inject the Fragment:

public class MyFragment extends Fragment{

    @Inject Bus mBus;

    public void onAttach(){
        Injector.inject(this);
    } 

}
JJD
  • 50,076
  • 60
  • 203
  • 339
Emmanuel
  • 13,083
  • 4
  • 39
  • 53
  • You misunderstood the question. The integration of Otto is not the problem. It already works in general. – JJD May 21 '14 at 07:53
  • I am not sure I understand: Do you suggest I can omit `((MyApp) getActivity().getApplication()).getObjectGraph().inject(this);` in all fragments assuming that I put `@Inject Bus mBus;` in each fragment? Please extend your answer to clarify. – JJD May 21 '14 at 12:48
  • Yes, you can avoid that line if you `@Inject` the `Bus` on a `Application` class and call `ObjectGraph.inject(this) on it. This works because as soon as you make that call, Dagger will have a reference of a `Bus` to use anywhere in your app. We can chat if this still doesn't make sense. – Emmanuel May 21 '14 at 12:52