3. Setting up the Dagger injection framework. [PR|TAG]

The dependency injection flow is as follows.

Application injects Activities Activity injects Fragments Fragment injects child Fragments

Dependencies are shared from top to bottom. Activities have access to Application @Singleton dependencies. Fragments have access to Application @Singleton and Activity @PerActivity dependencies. Child fragments have access to Application @Singleton , Activity @PerActivity , and (parent) Fragment @PerFragment dependencies.

Note: This guide does not show how to inject Services, IntentServices, BroadcastReceivers, and ContentProviders to keep the guide at a reasonable size. You, the reader, should be able to easily figure this out on your own once you finish reading this guide. To get started, take a look at the base framework types; DaggerService , DaggerIntentService , DaggerBroadcastReceiver , and DaggerContentProvider .

Achieving this flow is straightforward.

First, create the custom scope annotations; @PerActivity , @PerFragment , and @PerChildFragment .

The @PerActivity scoping annotation specifies that the lifespan of a dependency be the same as that of an Activity. This is used to annotate dependencies that behave like a singleton within the lifespan of an Activity, Fragment, and child Fragments instead of the entire Application.

The @PerFragment custom scoping annotation specifies that the lifespan of a dependency be the same as that of a Fragment. This is used to annotate dependencies that behave like a singleton within the lifespan of a Fragment and child Fragments instead of the entire Application or Activity.

The @PerChildFragment custom scoping annotation specifies that the lifespan of a dependency be the same as that of a child Fragment (a fragment inside a fragment that is added using Fragment.getChildFragmentManager() ). This is used to annotate dependencies that behave like a singleton within the lifespan of a child Fragment instead of the entire Application, Activity, or parent Fragment.

Note: This setup does not support a child fragment within a child fragment as conflicting scopes will occur (compile time error). Child fragments within child fragments should usually be avoided. However, if another level of child fragment is required, then another scope would need to be created (perhaps @PerGrandChild custom scope annotation).

There is no @PerApplication custom scope annotation. @Singleton is used to specify that the lifespan of a dependency be the same as that of the Application.

Question: Why not create a @PerApplication custom scope instead of using @Singleton ? Third party libraries / dependencies use @Singleton , if they use dependency injection. If you use @PerApplication instead of the standard @Singleton scope, then Dagger will not be able to automatically inject @Singleton scoped dependencies.

Next, create the App , AppModule , and AppComponent , which is the entry point of the entire dependency injection setup.

The entry point of all dependency injection is the App , which implements HasActivityInjector that provides a dagger injected DispatchingAndroidInjector<Activity> . This indicates that activities are to participate in dagger.android injection.

The top-most level injection occurs in onCreate with DaggerAppComponent.create().inject(this) , which is a class that is generated by Dagger during compile-time based on the AppComponent .

Note: The App could extend DaggerApplication instead of implementing HasActivityInjector . However, inheritance should be avoided so that the option to inherit from something else later on is open. E.G. the App needs to extend MultiDexApplication (multidex is not a great example here since the application can install it without having to extend it- it’s just a hypothetical). The base framework type DaggerApplication contains a lot more code than what we have, which is not necessary unless we need to inject a Service , IntentService , BroadcastReceiver , or ContentProvider (especially ContentProvider ). In the case that we do need to inject other types besides Activity and Fragment or if you know that your Application does not need to extend something else, then it may be worth it to just extend DaggerApplication instead of writing more dagger code ourselves.

The AppModule is an abstract class that is annotated with the @Module annotation and includes the AndroidInjectionModule , which contains bindings to ensure the usability of dagger.android framework classes. The AppModule is empty right now but we will add stuff to it later.

The AppComponent is annotated with @Component and @Singleton to indicate that its modules ( AppModule ) are to provide @Singleton scoped or unscoped dependencies.

Next up is to create the base classes to be used throughout the app; BaseActivity , BaseActivityModule, BaseFragment , BaseFragmentModule , and BaseChildFragmentModule .

The BaseActivity contains dagger.android code that is very similar to the code in App . The only difference is that the BaseActivity implements HasFragmentInjector , indicating that fragments are to participate in dagger.android injection.

Note: The BaseActivity could extend DaggerActivity instead of implementing HasFragmentInjector . However, inheritance should be avoided so that the option to inherit from something else later on is open. Note: For support Fragment and AppCompatActivity users, take a look at this [PR] for the migration guide to using support APIs. The latest support API setup is available in the [master-support] branch. Question: Why is FragmentManager injected into the BaseActivity ? Why not just use the getFragmentManager() method? Short answer is to enable ease of mocking and verification in tests. Read this [PR] for a more detailed answer.

The injection occurs in onCreate before the call to super.

A FragmentManager named BaseActivityModule.ACTIVITY_FRAGMENT_MANAGER is also injected. The name is necessary here to avoid conflicts between the activity’s FragmentManager and the fragment’s child FragmentManager during injection.

Note: We may also create our own custom @Qualifier instead of using @Named to distinguish between the Activity and Fragment (child) FragmentManager . I wrote a long rant discussing @Qualifer and @Named and the advantages / disadvantages of each here.

The addFragment method provides subclasses the ability to add fragments. This is unused now but will be used later on.

Question: What is that @IdRes annotation for int containerViewId ? @IdRes is a part of the Android support annotations library that “denotes that an integer parameter, field or method return value is expected to be an id resource reference”. For a full list of support annotations, click here. The Android support annotations library comes with our Dagger 2.11 and Butterknife 8.7 dependencies. However, you should declare the support annotations library as a separate dependency. Visit the official documentation to learn more.

The BaseActivityModule provides the base activity dependencies; the activity Context and the activity FragmentManager named ACTIVITY_FRAGMENT_MANAGER . The module of the subclasses of the BaseActivity are required to include the BaseActivityModule and provide a concrete implementation of the Activity. An example of this will be shown later.

Question: I am getting a runtime error, IllegalStateException module must be set , after making some modifications to this project. How do I fix it? What is @Binds ? How is it different from @Provides ? The most likely issue is that you are attempting to use @Provides on a non-static method of an abstract module. Read more about it here. In that article, I also explain what @Binds is and how its different from @Provides . Note: Scoping the Context activityContext(Activity activity) with @PerActivity is not necessary since the Activity instance will always be unique (new instances of it will not be created even without any scope). In general, providing Application , Activity , Fragment , Service , etc does not require scoped annotations since they are the components being injected and their instance is unique. The same thing applies to static FragmentManager activityFragmentManager(Activity activity) . The Activity instance is unique so the FragmentManager it returns always come from the same Activity . Thus, the @PerActivity is not necessary here as the scope is implicitly per activity (literally). However, using scope annotations in these cases makes the module easier to read. We wouldn’t have to look at what is being provided in order to understand its scope. I choose readability and consitency here over (negligible) “performance/optimization”. (Yes, I read up on the DoubleCheck wrapper around scoped dependencies and its one time synchronization block. I still abide by my statement given the following suporting materials; [1], [2]. I don’t want to digress further but essentially the synchronization cost only comes into play when multiple threads attempt to access the same locked resource at the same time. Most dependency injection setups do not incur this synchronization penalty as injection usually happens in only one thread.)

The BaseFragment , like the BaseActivity , implements HasFragmentInjector indicating that child fragments are to participate in dagger.android injection.

Note: The BaseFragment could extend DaggerFragment instead of implementing HasFragmentInjector . However, inheritance should be avoided so that the option to inherit from something else later on is open. Question: What about DialogFragments ? How are they injected? Someone has asked this question here, which I have answered here. Question: Why is activity Context and child FragmentManager injected into the BaseFragment ? Why not just use the getContext() and getChildFragmentManager() methods respectively? Short answer is to enable ease of mocking and verification in tests. Read this [PR] for a more detailed answer.

The injection occurs in onAttach before the call to super.

Note: We place AndroidInjection.inject(this) in onAttach(Context) for Android versions M (API level 23) and above and also in onAttach(Activity) for Android versions L (API level 22) and below. The reason is that onAttach(Activity) has been deprecated starting at API level 23. Do not only perform the injection in onAttach(Context) because it will not be invoked by devices running Lollipop (API level 22) and below, which will cause a NullPointerException when trying to access Fragment dependencies. I have learned this the hard way. Take a look at this [BUG] and the [BUGFIX]. Another thing to note is that using support Fragment does not require the above API level checks. We would only need to call AndroidSupportInjection.inject(this) in onAttach(Context) because support Fragments have and invokes onAttach(Context) even for API level 22 and below, which makes sense given that the entire goal of the support libs is to give older versions of Android code that’s available only in newer API levels. Take a look at this [PR] for the migration guide to using support APIs. The latest support API setup is available in the [master-support] branch.

The activity Context , which is provided by the BaseActivityModule , is injected here as well as a FragmentManager named BaseFragmentModule.CHILD_FRAGMENT_MANAGER . As previously mentioned in the BaseActivity , the name is necessary here to avoid conflicts between the activity’s FragmentManager and the fragment’s child FragmentManager during injection.

The addChildFragment method provides subclasses the ability to add child fragments. This is unused now but will be used later on.

Child fragments also extend BaseFragment to avoid code duplication, which will become more apparent when refactoring to Model-View-Presenter (MVP) architecture later on. The trade-off is that child fragments will have access to the childFragmentManager and addChildFragment , which should not be used by child fragments unless grandchildren (child fragment within a child fragment) are supported.

The BaseFragmentModule provides the base fragment dependencies; so far only the child FragmentManager named CHILD_FRAGMENT_MANAGER . The module of the subclasses of the BaseFragment are required to include the BaseFragmentModule and provide a concrete implementation of the Fragment named FRAGMENT . An example of this will be shown later.

Note: Similar to the BaseActivity and BaseFragment FragmentManager names, a different name for the Fragment dependency is required in order to remove any ambiguity about which fragment is being provided in a child fragment. For example, we have parent fragment P and child fragment C. Parent fragment P will provide the Fragment reference using the BaseFragmentModule.FRAGMENT name whereas child fragment C will provide the Fragment reference using the BaseChildFragmentModule.CHILD_FRAGMENT name. If the parent and child fragment dependencies are not uniquely named, then the child fragment and its dependencies will not know which Fragment is provided to it because both dependencies have the same type of Fragment . It could be the parent fragment or the child fragment. Hence the ambiguity, which causes a compile error of "android.app.Fragment is bound multiple times". Note: The Fragment.getChildFragment() method is only available beginning with API level 17. Supporting API levels below 17 down to 14 requires the use of AppCompatActivity , support Fragment , and dagger.android.supportAPIs. Take a look at this [PR] for the migration guide to using support APIs. The latest support API setup is available in the [master-support] branch.