Search code examples
dagger-2android-architecture-componentsdagger

Why double inject an Android Application in Dagger?


Looking at the source code for the Android Architecture Components sample GithubBrowerSample, I don't understand the point of double injecting the githubApp.

Wouldn't the inject method be enough? Why do it need both of them in the same sentence?

public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance Builder application(Application application);
        AppComponent build();
    }
    void inject(GithubApp githubApp);
}

And they use it like:

public static void init(GithubApp githubApp) {
        DaggerAppComponent.builder().application(githubApp)
                .build().inject(githubApp);

Solution

  • As Thomas Broyer described, you've got two separate directions to set up: You want the Dagger graph to know how to get to your Application instance, and you want to get access to certain bindings out of the dependency graph.

    The @BindsInstance line in the Builder creates a binding for Application set to the instance you pass in. It sounds like you understand this part.

    However, after you've created your Component, presumably you want to use it. Let's say you want to get fully-injected instances of classes Dep1, Dep2, and Dep3 out of your graph. One way you could do this is to create methods on your Component that get the instances:

    @Singleton @Component(/* ... */) interface AppComponent {
        // [builder snipped out here]
    
        fun getDep1(): Dep1
        fun getDep2(): Dep2
        fun getDep3(): Dep3
    }
    

    And then you call those as part of your App creation.

    var appComponent = DaggerAppComponent.builder().application(githubApp).build()
    var dep1 = appComponent.getDep1()
    var dep2 = appComponent.getDep2()
    var dep3 = appComponent.getDep3()
    // Use dep1, dep2, and dep3 here.
    

    However, you can also create a single-arg method, which is typically a void method called inject. This populates all of the @Inject-annotated fields and calls all of the @Inject-annotated methods on the instance you pass in. If GitHubApp has @Inject-annotated-fields (and it does), the call to inject lets you skip defining all of the getters on the Component. That reduces all of the above code to:

    DaggerAppComponent.builder().application(githubApp)
        .build().inject(githubApp)
    

    ...which is what you see in the demo.