At Android Dev Summit 2019, Google stated its opinion on how to develop an app in Android. Manuel Vivo and Daniel Santiago have both presented a great talk on what Google thinks of dependency injection and an improvement plan for Dagger 2 in the below video.

As a fan of Android, Kotlin, and Dagger 2, I’ll summarize the content for quick read in this blog.

It short, for dependency injection, Google made it loud and clear:

Use Dagger 2 for your Medium / Large Android Project

In case you don’t know what’s Dagger 2 is, read this Dagger 2 for Dummies for a fun version of learning Dagger 2. And in you don’t know what the different between Dependency Injection vs Service Locator, read this blog.

Improvement for Dagger 2

Google is fully aware that Dagger 2 has its challenges, such as a steep learning curve (hey, ready Dagger 2 for Dummies or 3 lines example, it’s not that steep), it’s not as compatible with Kotlin and the Android Framework (e.g. need to self-inject). So they come up with a nice plan, that I’m excited about.

Let’s me summarize their plan as below

1. Dagger 2 will work better with Kotlin

Support @Module annotation Object classes

Currently we need to have @JvmStatic as shown below

@Module

object DatabaseModule {

@Provides

@JvmStatic

fun provideDB(ctx: Context): AppDatabase {

// ...

}

}

The plan is to remove the need of it 🎉.

@Module

object DatabaseModule {

@Provides

fun provideDB(ctx: Context): AppDatabase {

// ...

}

}

Understand Qualifier Annotations

Currently we need to have a field as shown below for Qualifier name

class ProfileActivity: AppCompatActivity() {

@Inject

@field:Username

lateinit var username: String

}

The plan is to remove the need of it 🎉.

class ProfileActivity: AppCompatActivity() {

@Inject

@Username

lateinit var username: String

}

Understand Kotlin Wildcards

Currently we need to have @JvmSupressWildcards when having Kotlin wildcard:

@Module

class ConfigurationModule {

@Provides

fun provideOptions(): List<@JvmSupressWildcards String> {

// ...

}

}

The plan is to remove the need of it 🎉.

@Module

class ConfigurationModule {

@Provides

fun provideOptions(): List<String> {

// ...

}

}

Personally I think one thing is still missing, that is the need of lateinit var for all the injected object. I’m okay with lateinit , but as a public accessible var , this risks it being modified externally. It makes Dagger not as nice as Koin or Kodein that’s more compatible with Kotlin. Daniel Santiago, can Google see how that could be tackled?

2. Simpler Dagger 2 Approach

Simplify Injection

Currently to use the out-of-box Dagger 2 for Android, the only way to inject into the Activity is as below, i.e. explicitly get the component and perform self injection:

class PlayingActivity: AppCompactActivity() {

@Inject

lateinit var player: Player override fun onCreate() {

val appComponent = (applicationContext as MyApp).appComponent

appComponent.inject(this)

}

}

Even with Dagger Android , you’ll still need to inherit from a special Dagger 2 Activity class as below, with the self injection happens behind the scene in DaggerAppCompactActivity class.

class PlayingActivity: DaggerAppCompactActivity() {

@Inject

lateinit var player: Player

}

Google plans to introduce a new annotation named @EntryPoint to simplify it 🎉. (probably the death of Dagger Android ? 😇 )

@EntryPoint

class PlayingActivity: AppCompactActivity() {

@Inject

lateinit var player: Player

}

Not only will they support injection of common dependency, but also the ViewModel 🎉.

@EntryPoint

class PlayingActivity: AppCompactActivity() {

@Inject

lateinit var playbackViewModel: PlaybackViewModel

}

Predefined Components

In using Dagger 2, who doesn’t define AppComponent ? And it is Singleton , right? As below…

@Singleton

@Component(modules = [DatabaseModule::class]

interface AppComponent {

fun injectActivity(activity: PlayingActivity)

} @Module

object DatabaseModule {

@Provides

@Singleton

fun provideDatabase (...): Music Database {

// ...

}

}

Google’s plan is moving forward, provide out-of-the-box predefined SingletonComponent (in replacement of the manually created AppComponent ) 🎉. We can easily add the Module into it using @InstallIn annotation.

@Module

@InstallIn(SingletonComponent::class)

object DatabaseModule {

@Provides

@Singleton

fun provideDatabase (...): Music Database {

// ...

}

}

Not only will the SingletonComponent be provided, Google will also provide the predefined ActivityComponent , FragmentComponent , and ServiceComponent 🎉.

With this, we only need to focus on binding instead of manually creating the boilerplate code of the component.

While we have this predefined components, we could still use the native Dagger 2 component for any customization needed. That’s for those already with experience using Dagger 2.

3. Dagger 2 Testing with EntryPoint

With @EntryPoint to be introduced by Google, they also considered simplifying the test by providing its Rule , i.e. TestEntryPointRule that will provide a component for each test 🎉.

We could also further configure our test cases with @TestModule to customize the some of the dependencies as mock dependencies accordingly 🎉.

@RunWtih(AndroidJUnit4::class)

class PlaybackTest {

@Rule

val testEntryPointRule = TestEntryPointRule() @TestModule

object class PlaybackTestModule {

@Provides

fun provideFakeDB() = FakeMusicDatabase()

} @Inject

lateinit var player: Player val activity: PlaybackActivity

}

4. Better integration with Jetpack Library

Last but not least, more Dagger 2 will be seen across Jetpack Library such as Fragments, ViewModel, WorkManager, etc.

So better start considering learning Dagger 2 for your Android 2 Development.