Migrating Tokopedia Academy App From Dagger Android Into Hilt!

Yehezkiel L
Aug 14 · 5 min read
Image for post
Image for post
Dagger Hilt Android

Everyone who has ever used Dagger might be confusing in the beginning, or maybe in some period. Dagger’s rule is also quite stringent. For me, Dagger has a high learning curve. We need Component, Module, and have to Inject in a specific class. Then Google hears our pain with inventing Hilt to make Dagger more fun and straightforward. More about superpower and advantage of Hilt can be found here.

Image for post
Image for post

Hilt is a dependency injection library built on top of Dagger, so it has all ability from Dagger, such as compile-time correctness, runtime performance, scalability, and Android Studio support that Dagger provides. I already tried Hilt once, and this is amazing and simple; it reduces even much code in the simple sample project below.

Code reduce with hilt
Code reduce with hilt

In this article, I will convert Tokopedia Academy Movie App project from Dagger Android to Hilt. Before starting, to clarify the context me with other team members have been created a Movie App project for Tokopedia Academy, which was held before. In general, this academy has the objective of conveying Tokopedia Android Technology in a fundamentally.

Getting started with Hilt

First, add Hilt plugin in build.gradle root project.

buildscript {
...
dependencies {
...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
}
}

Then, add Hilt dependencies in your build.gradle application level. Also, don’t forget to enable Java 8, since Hilt uses Java 8.

...
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

android {
...
}

dependencies {
implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}

Migrating Application

Below is the Application class using Dagger Android, We need to override DaggerApplication() and implement the functions to tell Dagger about Application.

MovieApplication With Dagger 2

Below is the Application with Hilt, pretty neat, right? We even delete all the function and leave it empty. If using Hilt, the app must contain Application with @HiltAndroidApp to attach Dagger to the Application of your apps and code generation.

MovieApplication With Hilt

Hilt also can provide another class to specify and generate component in which class you want to provide, like :

  • Application (by using @HiltAndroidApp)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Migrating Inject View

If you’re using Dagger 2 or Dagger Android, your view like Activity/Fragment will have DaggerComponent.inject or override DaggerFragment() code.

In our project We override DaggerFragment() :

MovieListFragment With Dagger 2

With Hilt, We are free to remove all of this boilerplate into :

From this code We change DaggerFragment() into Fragment()or if you using Dagger 2, just remove YourComponentDaggerModule.inject()

Then change into @AndroidEntryPoint annotation. This annotation behaves like @HiltAndroidApp in the previous section. *NOTE: If you annotate the Fragment, you also must annotate Android classes that depend on it. For example, We need to annotate MovieDetailActivity.kt too.

Migrating Module

Sometimes if you cannot provide constructor-injected. Like in this project, We need Retrofit instance. But Dagger still doesn’t know how to provide the Retrofit because Dagger can’t create the Retrofit object by itself, and Retrofit is an external library that Dagger doesn’t know. So We need to provide the Retrofit instance manually inside our @Module.

With Hilt, module behaves the same as Dagger, but We need one additional annotation @InstallIn().@InstallIn(ApplicationComponent::class) will tell Hilt where the module should be provided and generate components for us. For example, in this snippet code, this code acts to provide Retrofit in MovieApplication.kt , so when MovieApplication.kt is created, the Retrofit instance also created.

AppModule With Hilt

As We said before, Hilt will generate components for us, so what? Ya! Exactly what you thought. We don’t even need our legacy components here, so We remove all of our components!

Image for post
Image for post
Old AppComponent.kt

Another generated component you can use :

Image for post
Image for post
source

Migrating View Model Injector Factory

Last but not least, this project uses ViewModel, and We think it’s widespread that many new apps use this too. Usually, if we use ViewModel we need to provide our ViewModel and ViewModelFactory with Dagger. This also has a problem with boilerplate code like :

ViewModelFactory With Dagger 2

and something like this in your module :

MovieListModuleProvider With Dagger 2

We can delete all of those codes!

Image for post
Image for post
Safely Delete MovieListModuleProvider.kt
Image for post
Image for post
Safely Delete ViewModelFactory.kt

Hilt includes extensions for providing classes from other Jetpack libraries and currently supports the following Jetpack components:

  • ViewModel
  • WorkManager

First, add new dependencies in your app/build.gradle, and don’t forget to sync gradle.

implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0alpha01'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

Then We change @inject constructor in our ViewModel into @ViewModelInject . Here we go, our ViewModel already injected with Factory.

Conclusion

That’s all the migrating our project from Dagger Android into Hilt. From here, We have s conclusion and pros/cons with Android Hilt.

Pros :

  1. It’s now super easy to use Dagger with Hilt
  2. Reduce more codes
  3. Reduce boilerplate
  4. Jetpack Integration
  5. It’s easy to migrate, especially if you already have Dagger in your legacy code

Cons :

  1. Hilt in Dynamic Features need extra components and inject similar with Dagger 2

If you have Dynamic Feature module, you need an extra component and also need manually inject like Dagger 2 do, like :

class LoginActivity : AppCompatActivity() {

@Inject
lateinit var loginAnalyticsAdapter: LoginAnalyticsAdapter

override fun onCreate(savedInstanceState: Bundle?) {
DaggerLoginComponent.builder()
.context(this)
.appDependencies(
EntryPointsAccessors.fromApplication(
applicationContext,
LoginModuleDependencies::class.java
)
)
.build()
.inject(this)

super.onCreate(savedInstanceState)
...
}
}

Tokopedia Application itself has many Dynamic Feature Modules but several modules still not implemented yet. This can cause inconsistency between modules because if we create a new Dynamic Features module we need to create an extra component and even we need to manual inject in view. We also need to change the existing DF Module to DF Hilt Support. So that’s why we need to gather more data to ensure Hilt fit perfectly with our existing code. Source

2. Custom Scope and Component also need more research

Image for post
Image for post

Full Project can be found here :

Then here is the PR :

Source :

https://developer.android.com/training/dependency-injection/hilt-jetpack

https://developer.android.com/training/dependency-injection

Deep Dive Here :

https://dagger.dev/hilt/

Tokopedia Engineering

Story from people who build Tokopedia

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store