2

I am attempting to use Dagger as my Android app's dependency injection library. In my project, I have different Android modules in the project representing different flavors of the app. I want to use dependency injection to allow each module to define its own navigation menu.

My MenuFragment class requires an instance of my interface (MenuAdapterGenerator):

public class MenuFragment extends Fragment {

    @Inject
    protected MenuAdapterGenerator generator;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
        //this.generator is always null here, though shouldn't it be injected already?:
        BaseExpandableListAdapter adapter = new MenuAdapter(inflater, this.generator);
    }
}

This is what my menu module looks like:

@Module (
    injects = MenuAdapterGenerator.class
)
public class MenuDaggerModule {
    public MenuDaggerModule() {
        System.out.println("test");
    }

    @Provides @Singleton MenuAdapterGenerator provideMenuAdapterGenerator() {
        return new MenuNavAdapterGenerator();
    }

}

Here is the overall app-level module (which includes this MenuDaggerModule):

@Module (
    includes = MenuDaggerModule.class,
    complete = true
)
public class OverallAppModule {

}

(Edit:) Here is my MainActivity class which creates the object graph:

public class MainActivity extends Activity {

private ObjectGraph objGraph;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.objGraph = ObjectGraph.create(OverallAppModule.class);
    this.mainWrapper = new MainWrapper(this, this.objGraph);
    this.setContentView(R.layout.activity_main);
    //Other instantiation logic
}

(Edit:) And here is where I actually make my MenuFragment (in MainWrapper):

public class MainWrapper {

    public MainWrapper(Activity activity, ObjectGraph objGraph) {
        this.menu = new MenuFragment();
        this.objGraph.inject(this.menu);
        //I have no idea what the above line really does
        FragmentManager fm = this.activity.getFragmentManager();
        FragmentTransaction t = fm.beginTransaction();
        t.replace(R.id.menu_fragment, this.menu);
        t.commit();
    }

}

Why is my module's provideMenuAdapterGenerator method not called to inject my MenuAdapterGenerator? If I set a breakpoint in that method, it is never tripped. But the MenuDaggerModule is getting created, because System.out.println("test"); is being hit.

My understanding is that if the MenuDaggerModule is created (which it is), Dagger should then use that provideMenuAdapterGenerator() anytime a @Injects MenuAdapterGenerator is encountered. What do I have wrong?

John D.
  • 2,521
  • 3
  • 24
  • 45

1 Answers1

1

Dagger is a lot of magic, but not that much. You still need to tell Dagger to inject your instances.

I will assume you've got a reference to your MenuFragment in your MainActivity. When you create your Fragment, you need to tell Dagger to inject it, by calling ObjectGraph.inject(T):

MenuFragment fragment = new MenuFragment();
this.objectGraph.inject(fragment);
Transaction transaction = getFragmentManager().beginTransaction();
// etc.

Dagger will now notice the @Inject annotation on your MenuAdapterGenerator, and call provideMenuAdapterGenerator() to inject it.


I'd like to recommend another answer of mine, which discusses Constructor Injection. Although Fragments are one of the few cases this is not possible (along with Activitys and Views), you might want to consider using that technique for injecting possible other custom classes.

Community
  • 1
  • 1
nhaarman
  • 98,571
  • 55
  • 246
  • 278
  • Edited the above code to show your suggestions, yet my generator is still null :-/ – John D. Jan 19 '15 at 22:37
  • Whoops, my generator was still null because I wasn't actually using that instance I created by "new". Changed my code to use it, and it's working. Excellent, thanks for your help. Though I see less of an advantage to using DI at all if you still have to do all this manual wiring. I guess the true benefits come in when you create a second flavor of your app. – John D. Jan 19 '15 at 22:50
  • 1
    Great! About your DI point, it *will* become easier when your app gets bigger. Especially if you're using Constructor Injection. The way you're using Dagger now is kind of a 'hack', because you can't (shouldn't) use constructors with arguments in `Fragment`s. – nhaarman Jan 19 '15 at 23:10
  • Hmm, but I'm not using any constructors with arguments on a Fragment? Also, is it common to have to pass the ObjectGraph around via constructors everywhere? – John D. Jan 21 '15 at 19:26
  • 1
    No, you're not, and that's a good thing. And it shouldn't be too common to pass it around. Dagger should be able to instantiate your whole instance tree. – nhaarman Jan 21 '15 at 19:31
  • Ok I think I'm 98% of the way to comprehending Dagger. My last question: how do you deal with nested Fragments? My MainApplication creates a parent Fragment. This parent Fragment has a navbar Fragment as a member. I want to inject my MainApplication into the navbar Fragment (because it contains the logic for opening my drawer menu). Can I do this without passing ObjectGraph into the parent? – John D. Jan 21 '15 at 21:24
  • 1
    Perhaps you're better off creating a new question so you can show your code structure. – nhaarman Jan 21 '15 at 21:33
  • http://stackoverflow.com/questions/28077618/using-dagger-with-nested-fragment-and-views – John D. Jan 21 '15 at 21:57