Esperanz0
Esperanz0

Reputation: 1586

Dagger 2 Good practices to build components in Application class

I know probably there is no clear answer for this question.

But I would like to know Your opinions and maybe new ideas.

I'm wondering which of the following options is the best/right/correct way to build the app-level Dagger Component in Application class.


Example 1:

public class MyApp extends Application {

    private NetComponent mNetComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        mNetComponent = DaggerNetComponent.builder()
                .appModule(new AppModule(this)) 
                .netModule(new NetModule("https://api.github.com"))
                .build();
    }

    public NetComponent getNetComponent() {
        return mNetComponent;
    }
}

Usage:

((MyApp) getApplication()).getNetComponent().inject(this);

Example 2:

 class MyApplication extends Application {

    private static MyComponent component;

    @Override
    void onCreate() {
        component = DaggerMyComponent.builder()
                .contextModule(new ContextModule(getApplicationContext()))
                .build();
    }

    public static MyComponent getMyComponent() {
        return component;
    }
}

Usage:

MyApplication.getMyComponent().inject(this)

Example 3:

class CustomApplication: Application() {
    lateinit var component: SingletonComponent
        private set

    override fun onCreate() {
        super.onCreate()
        INSTANCE = this
        component = DaggerSingletonComponent.builder()
                       .contextModule(ContextModule(this))
                       .build()
    }

    companion object {
       private var INSTANCE: CustomApplication? = null

       @JvmStatic
       fun get(): CustomApplication = INSTANCE!!

    }
}

Then:

class Injector private constructor() {
    companion object {
        @JvmStatic
        fun get() : SingletonComponent = CustomApplication.get().component
    }
}

Usage:

Injector.get().catRepository()

Example 4:

 class App : Application() {

    var repositoryComponent: RepositoryComponent? = null
    var appComponent: AppComponent? = null

    override fun onCreate() {
        super.onCreate()
        instance = this
        appComponent = DaggerAppComponent.builder().application(this).build()
        repositoryComponent = DaggerRepositoryComponent.builder().build()
    }

    companion object {

        private var instance: App? = null

        fun get(): App {
            return instance!!
        }
    }
}

Usage:

 App.get().repositoryComponent!!.inject(this)

What do you think about this? Is there any better / cleaner way to do this? Maybe provided examples are fine? Or maybe just one of them?

I will be grateful for any good examples / tips / advices.

Thanks!

Upvotes: 3

Views: 1354

Answers (1)

EpicPandaForce
EpicPandaForce

Reputation: 81588

Okay, no one answered in 5 days so it's my turn, despite my bias :p

  • Option #1

((MyApp) getApplication()).getNetComponent().inject(this);

It's an "ok" version of doing things, except for two things.

First, the name. NetComponent isn't really for networking, it's the app-global singleton component, so it should be either called SingletonComponent or AppComponent. But naming it NetComponent is disingenuous, it's typically responsible for everything else too.

Second problem is that you need a reference to Context to access your dependency graph, making Context actually be a dependency rather than it being provided to you.

  • Option #2

MyApplication.getMyComponent().inject(this)

This is a perfectly fine way of doing things, but you need to know that to reach your object graph, you need to access the static method of MyApplication.

  • Option #3

Injector.get().inject(this)

Internally, this solution actually just calls over to get the app component, public static AppComponent get() { return MyApplication.getInstance().getComponent(); }

The benefit is that getComponent() is exposed via an instance method of Application, so it could be theoretically swapped out.

Also, invoking a method on something called Injector.get() is more obviously an "injector" than, well, an application class.

As for whether you use .catRepository() or .inject(this), it's up to you; but I personally prefer calling the provision methods to get the deps in Activity/Fragment, because listing the member-injection targets adds a lot of clutter to the component over time.

4.)

App.get().repositoryComponent!!.inject(this)

You can ditch the !! if repositoryComponent is a lateinit var.

Having two components for the same scope (and therefore two different object graphs) will only cause trouble, out of all of the options, this is the worst.


In my opinion, the 3rd option is the best. Technically it's the same as option #2 with an additional "indirection" through the instance method of Application that actually returns the component.

Upvotes: 3

Related Questions