Dependency Injection in Android – Dagger2 and Hilt - Textnotes

Dependency Injection in Android – Dagger2 and Hilt


Learn how to use Dagger2 and Hilt for Dependency Injection in Android applications. Discover how these tools help manage dependencies efficiently, making your code more modular, testable, and maintainable.

What is Dependency Injection (DI)?

Dependency Injection (DI) is a design pattern used to implement Inversion of Control (IoC), where the control of creating objects and their dependencies is delegated to an external entity. This makes the code more modular, easier to test, and more maintainable by decoupling classes from their dependencies.

In Android, Dependency Injection is crucial because it allows you to inject dependencies like network clients, databases, or repositories into your activities, fragments, and view models without manually initializing them each time.

Two popular DI frameworks in Android are Dagger2 and Hilt. Hilt is built on top of Dagger2 but simplifies its setup and usage.

i) Using Dagger2 for Dependency Injection

Dagger2 is a fully static, compile-time dependency injection framework for Java and Android. It provides a robust and scalable way to manage dependencies in Android projects, but it requires more setup and boilerplate code compared to Hilt.

Steps to Use Dagger2

  1. Add Dependencies:

First, add the necessary dependencies to your build.gradle files.


// In your app-level build.gradle file
implementation 'com.google.dagger:dagger:2.38.1'
kapt 'com.google.dagger:dagger-compiler:2.38.1'
  1. Create the Dependency Classes:

Let’s say you have a NetworkService class that you want to inject into your activity:


public class NetworkService {
public void fetchData() {
// Network request code
}
}
  1. Create a Module to Provide Dependencies:

A Module in Dagger2 provides methods that supply instances of your dependencies. Use the @Module annotation to define it and the @Provides annotation for each method that provides a dependency.


@Module
public class NetworkModule {
@Provides
public static NetworkService provideNetworkService() {
return new NetworkService();
}
}
  1. Create a Component:

A Component is responsible for connecting the provided dependencies with the classes that need them. It acts as a bridge between your Module and your target class.


@Component(modules = NetworkModule.class)
public interface AppComponent {
void inject(MainActivity mainActivity);
}
  1. Inject Dependencies:

Finally, inject the dependency into the target class (e.g., an Activity or Fragment) using @Inject and AppComponent.


public class MainActivity extends AppCompatActivity {
@Inject
NetworkService networkService;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppComponent.create().inject(this); // Inject dependencies
// Now you can use the injected NetworkService
networkService.fetchData();
}
}

Benefits of Using Dagger2:

  1. Compile-time checks for dependencies.
  2. Scalable and flexible, especially in large applications.
  3. Efficient dependency resolution and lifecycle management.

ii) Using Hilt for Dependency Injection

Hilt is a modern, simplified version of Dagger2 that integrates seamlessly with Android. It reduces the boilerplate code required for Dagger2 and is officially recommended by Google for dependency injection in Android apps.

Steps to Use Hilt

  1. Add Dependencies:

To use Hilt, add the following dependencies to your project’s build.gradle files.

In your root build.gradle:


classpath 'com.google.dagger:hilt-android-gradle-plugin:2.38.1'

In your app-level build.gradle:


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

dependencies {
implementation 'com.google.dagger:hilt-android:2.38.1'
kapt 'com.google.dagger:hilt-compiler:2.38.1'
}
  1. Create a NetworkService Class:

Create your dependency class just like with Dagger2.


public class NetworkService {
public void fetchData() {
// Network request code
}
}
  1. Create a Hilt Module (Optional):

With Hilt, you can optionally create modules to provide dependencies. But in many cases, Hilt uses constructor injection directly, so this step is not always necessary.


@Module
@InstallIn(SingletonComponent.class)
public class NetworkModule {

@Provides
@Singleton
public static NetworkService provideNetworkService() {
return new NetworkService();
}
}
  1. Use @Inject for Constructor Injection:

With Hilt, the preferred method is constructor injection, where dependencies are automatically injected into classes through their constructors.


@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
NetworkService networkService;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Hilt will automatically inject NetworkService
networkService.fetchData();
}
}
  1. Use @AndroidEntryPoint:

To allow Hilt to inject dependencies into activities, fragments, services, etc., mark them with @AndroidEntryPoint.


@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
// Dependencies injected by Hilt
}
  1. Inject Dependencies in ViewModels:

Hilt also supports injecting dependencies into ViewModels.


@HiltViewModel
public class MyViewModel extends ViewModel {

private final NetworkService networkService;

@Inject
public MyViewModel(NetworkService networkService) {
this.networkService = networkService;
}

public void fetchData() {
networkService.fetchData();
}
}

Benefits of Using Hilt:

  1. Simpler than Dagger2, with reduced boilerplate code.
  2. Fully integrated with Android and recommended by Google.
  3. Supports constructor injection, which is cleaner and easier to maintain.
  4. Automatically handles lifecycle management of dependencies.
  5. Ideal for new Android projects.

Comparison – Dagger2 vs. Hilt

FeatureDagger2Hilt
Setup ComplexityHigh, requires more boilerplateLow, reduces boilerplate significantly
IntegrationRequires manual setup for Android componentsSeamlessly integrated with Android components
Dependency InjectionBased on components and modulesUses constructor injection and automatic binding
Official SupportGoogle-supported but more complexOfficial Google recommendation, simpler to use
UsageSuitable for large, complex appsIdeal for new apps or simple architectures

Conclusion

In this tutorial, we explored Dependency Injection in Android using Dagger2 and Hilt. While Dagger2 is a powerful and scalable solution for dependency injection, it comes with significant complexity. Hilt, on the other hand, is designed to simplify the DI process by reducing boilerplate code and integrating more seamlessly with Android, making it the preferred choice for modern Android development.

By using DI frameworks like Dagger2 or Hilt, you can make your Android code more modular, testable, and maintainable, especially as your app grows in size and complexity.