Skip to content

Dependency Injection

SuperDragonXD edited this page Jun 24, 2025 · 1 revision

Lawnicons uses Hilt for dependency injection (DI). Hilt is a DI library built on top of Dagger that simplifies Dagger setup and usage in Android applications. It helps us write more modular, testable, and maintainable code by managing how objects (dependencies) are created and provided to other objects.

Why use Hilt?

  • Reduced Boilerplate: Hilt significantly cuts down on the manual setup Dagger often requires.
  • Lifecycle Management: Hilt automatically manages the lifecycle of injected dependencies, tying them to standard Android component lifecycles (like Application, Activity, ViewModel).
  • Standardization: Provides a standard way to do DI in Android apps.
  • Testability: Makes it easier to replace real dependencies with test doubles (fakes or mocks) in your tests.

Key Hilt concepts and annotations in Lawnicons

You'll encounter these Hilt annotations throughout the codebase:

  • @HiltAndroidApp:
    • Applied to the LawniconsApplication.kt class.
    • This triggers Hilt's code generation, including a base class for your application that supports DI.
    • LawniconsApplication.class // Hilt needs to be initialized in an Application class
  • @AndroidEntryPoint:
    • Used on Android components like Activity (for example, MainActivity.kt).
    • It tells Hilt to prepare these components for injection. Hilt can then provide dependencies to these components.
  • @HiltViewModel:
    • Applied to ViewModel classes (for example, LawniconsViewModelImpl.kt).
    • This allows Hilt to create and provide ViewModel instances, along with their dependencies, to the UI layer (Activities or Composables).
  • @Inject constructor:
    • Used on the constructor of a class (for example, most Repository implementations like IconRepositoryImpl.kt).
    • This tells Hilt how to create instances of that class. If all of its constructor parameters can also be provided by Hilt, Hilt can automatically create it.
  • @Module:
    • Applied to classes that provide bindings for types that cannot be constructor-injected (like interfaces or classes from external libraries, such as Retrofit services).
    • Modules are typically located in the di/ and api/ packages.
    • Example: IconRepositoryModule.kt provides the IconRepository interface.
  • @Provides:
    • Used inside @Module classes on functions.
    • These functions tell Hilt how to create and provide instances of certain types.
    • Example: A function in GithubApiModule.kt annotated with @Provides creates and returns a GitHubContributorsAPI (Retrofit service) instance.
  • @InstallIn(...):
    • Used with @Module to specify which Hilt component(s) the module's bindings should be available in (for example, SingletonComponent::class makes bindings available application-wide, ViewModelComponent::class for ViewModels).

How dependencies flow

  1. Application Setup: LawniconsApplication is annotated with @HiltAndroidApp.
  2. Activity/Screen Setup: MainActivity is annotated with @AndroidEntryPoint.
  3. ViewModel Creation: When a Composable requests a ViewModel using hiltViewModel(), Hilt creates or provides an instance of that @HiltViewModel.
  4. ViewModel Dependencies: If a ViewModel's constructor (annotated with @Inject) requires, for example, an IconRepository, Hilt looks for how to provide IconRepository.
  5. Repository Provision:
    • Hilt finds a module (like IconRepositoryModule.kt) that has an @Provides function returning IconRepository.
    • This function might return an instance of IconRepositoryImpl.
    • If IconRepositoryImpl itself has an @Inject constructor (for example, requiring an Application context or an API service), Hilt provides those dependencies too.
  6. API Service Provision (Example):
    • If GitHubContributorsRepository (used by ContributorsViewModel) needs GitHubContributorsAPI, Hilt looks to a module like GithubApiModule.kt.
    • An @Provides function in that module configures and creates the Retrofit service instance for GitHubContributorsAPI.

This system allows classes to simply declare their dependencies in their constructors (or via field injection in certain Android components, though constructor injection is preferred), and Hilt takes care of constructing and providing those dependencies.

You can explore the modules in the di/ and api/ packages to see specific examples of how dependencies like Repositories and Retrofit services are provided.

Clone this wiki locally