Introduction
Hilt makes it easy to add dependency injection to your Android app. This tutorial will guide you through bootstrapping an existing app to use Hilt.
For more on the basic concepts of Hilt’s components, check out Hilt Components.
Gradle vs non-Gradle users
For Gradle users, the Hilt Gradle plugin makes usages of some Hilt annotations easier by avoiding references to Hilt generated classes.
Without the Gradle plugin, the base class must be specified in the annotation and the annotated class must extend the generated class:
@HiltAndroidApp(MultiDexApplication.class)
public final class MyApplication extends Hilt_MyApplication {}
@HiltAndroidApp(MultiDexApplication::class)
class MyApplication : Hilt_MyApplication()
With the Gradle plugin the annotated class can extend the base class directly:
@HiltAndroidApp
public final class MyApplication extends MultiDexApplication {}
@HiltAndroidApp
class MyApplication : MultiDexApplication()
Further examples assume usage of the Hilt Gradle plugin.
Hilt Application
All apps using Hilt must contain an
Application
class annotated with
@HiltAndroidApp
.
@HiltAndroidApp
kicks off the code generation of the
Hilt components and also generates a base class for your
application that uses those generated components. Because the code generation
needs access to all of your modules, the target that compiles your Application
class also needs to have all of your Dagger modules in its transitive
dependencies.
Just like other Hilt Android entry points,
Applications are members injected as well. This means you can use injected
fields in the Application after super.onCreate()
has been called.
Note: Since all injected fields are created at the same time in onCreate
,
if an object is only needed later or conditionally, remember that you can use a
Provider
to defer injection. Especially in the Application
class which is on
the critical startup path, avoiding unnecessary injections can be important to
performance.
For example, take the class called MyApplication
that extends
MyBaseApplication
and has a member variable Bar
:
public final class MyApplication extends MyBaseApplication {
@Inject Bar bar;
@Override public void onCreate() {
super.onCreate();
MyComponent myComponent =
DaggerMyComponent
.builder()
...
.build();
myComponent.inject(this);
}
}
class MyApplication : MyBaseApplication() {
@Inject lateinit var bar: Bar
override fun onCreate() {
super.onCreate()
val myComponent =
DaggerMyComponent
.builder()
...
.build()
myComponent.inject(this)
}
}
With Hilt’s members injection, the above code becomes:
@HiltAndroidApp
public final class MyApplication extends MyBaseApplication {
@Inject Bar bar;
@Override public void onCreate() {
super.onCreate(); // Injection happens in super.onCreate()
// Use bar
}
}
@HiltAndroidApp
class MyApplication : MyBaseApplication() {
@Inject lateinit var bar: Bar
override fun onCreate() {
super.onCreate() // Injection happens in super.onCreate()
// Use bar
}
}
For more details, see Hilt Application.
@AndroidEntryPoint
Once you have enabled members injection in your Application
, you can start
enabling members injection in your other Android classes using the
@AndroidEntryPoint
annotation. You can use @AndroidEntryPoint
on the following types:
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
Note that ViewModels are supported via a separate API
@HiltViewModel
. The following example shows how to add the
annotation to an activity, but the process is the same for other types.
To enable members injection in your activity, annotate your class with
@AndroidEntryPoint
.
@AndroidEntryPoint
public final class MyActivity extends MyBaseActivity {
@Inject Bar bar; // Bindings in SingletonComponent or ActivityComponent
@Override
public void onCreate() {
// Injection happens in super.onCreate().
super.onCreate();
// Do something with bar ...
}
}
@AndroidEntryPoint
class MyActivity : MyBaseActivity() {
@Inject lateinit var bar: Bar // Bindings in SingletonComponent or ActivityComponent
override fun onCreate() {
// Injection happens in super.onCreate().
super.onCreate()
// Do something with bar ...
}
}
Note: Hilt currently only supports activities that extend ComponentActivity
and
fragments that extend androidx library
Fragment
,
not the (now deprecated)
Fragment
in
the Android platform.
For more details, see @AndroidEntryPoint.
Hilt Modules
Hilt modules are standard Dagger modules that have an additional @InstallIn
annotation that determines which
Hilt component(s) to install the module into.
When the Hilt components are generated, the modules annotated with @InstallIn
will be installed into the corresponding component or subcomponent via
@Component#modules
or @Subcomponent#modules
respectively. Just
like in Dagger, installing a module into a component allows that binding to be
accessed as a dependency of other bindings in that component or any child
component(s) below it in the
component hierarchy. They can also be
accessed from the corresponding @AndroidEntryPoint
classes. Being installed in
a component also allows that binding to be scoped to that component.
Using @InstallIn
A module is installed in a Hilt Component by annotating the
module with the
@InstallIn
annotation. These annotations are required on all Dagger modules when using
Hilt, but this check may be optionally
disabled.
Note: If a module does not have an @InstallIn
annotation, the module will
not be part of the component and may result in compilation errors.
Specify which Hilt Component to install the module in by passing in the
appropriate Component type(s) to the @InstallIn
annotation.
For example, to install a module so that anything in the application can use it,
use SingletonComponent
:
@Module
@InstallIn(SingletonComponent.class) // Installs FooModule in the generate SingletonComponent.
final class FooModule {
@Provides
static Bar provideBar() {...}
}
@Module
@InstallIn(SingletonComponent::class) // Installs FooModule in the generate SingletonComponent.
internal object FooModule {
@Provides
fun provideBar(): Bar {...}
}
For more details, see Hilt Modules.