Java – Dagger 2 Good practices for building components in the Application class

Dagger 2 Good practices for building components in the Application class… here is a solution to the problem.

Dagger 2 Good practices for building components in the Application class

I understand that there may not be a definitive answer to this question.

But I would like to know your opinion and new ideas.

I would like to know which of the following options is the best/correct/correct way to build an app-level Dagger component in the 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!!

}
}

And 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 a better/cleaner way to do this? Maybe the provided example is good? Or maybe just one of them?

I would appreciate any good examples/tips/suggestions.

Thanks!

Solution

Well, no one answered in 5 days so it was my turn, although I was biased :p

  • Option #1

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

This is the “OK” version of doing things, except for two things.

First, the name. NetComponent is not really used for networking, it is an application global singleton component, so it should be called SingletonComponent or AppComponent. But it’s dishonest to name it NetComponent, which is usually responsible for everything else as well.

The second problem is that you need to reference the Context to access your dependency graph so that the Context is actually a dependency rather than provided to you.

  • Option #2

MyApplication.getMyComponent().inject(this)

This is a great way to do things, but you need to know that to access your object graph, you need to access MyApplication's static methods.

  • Option #3

Injector.get().inject(this)

Internally, this solution is actually just a call to get the application component, public static AppComponent get() { return MyApplication.getInstance().getComponent(); }

The benefit is that getComponent() is exposed through the instance method of Application, so it can theoretically be swapped out.

Also, calling a method named Injector.get() is more obviously an “injector” than an application class.

Whether to use .catRepository() or .inject(this) is up to you; But I personally prefer to call the provide method to get the deps in the activity/fragment, because listing the member injection target can cause a lot of confusion for the component over time.

4.)

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

If repositoryComponent is lateinit var, you can give up !!.

Using two components in the same scope (and therefore having two different object graphs) only causes trouble, and of all the options, it’s the worst.


In my opinion, the third option is the best. Technically, it’s the same as option #2, except that it’s extra “indirect” by actually returning the component’s Application instance method.

Related Problems and Solutions