Search this site
Embedded Files
Squirrel of Rama
  • Home
  • Institute Coaching Programs
  • Android curriculum
    • Android Topics
      • Notification
      • Broadcast & Broadcast Receiver
      • Content Providers
      • Activities
        • Activity and Lifecycle
        • Saving state
        • Tasks and the back stack
      • Services
        • Services
        • Foreground Service
        • Bound Service
      • Dependency Injection
      • Workmanager
      • Fragment Findings*
      • Navigation findings*
      • Permissions Findings*
      • Room & Datastore findings*
    • Kotlin Topics
      • Nullables
      • Exceptions
      • Conditions and Loops
      • Arrays
      • Collections
      • Collection Functions
      • Class & Object
      • OOP Concepts
      • Scope Function
      • Visibility Modifiers
      • Generics
      • Kotlin Classes Types
        • Enums
        • Sealed Class
        • Data Classes
        • Nested and inner classes
        • Object expressions and declarations
      • Kotlin Functions Types
        • Functions
        • Extension functions
        • Higher-order functions and lambdas
      • Couroutines
      • Kotlin Flows
    • Interview Questions
      • Android Interview Questions
  • Products
    • Shabri
    • WedExhibit
  • About
Squirrel of Rama
  • Home
  • Institute Coaching Programs
  • Android curriculum
    • Android Topics
      • Notification
      • Broadcast & Broadcast Receiver
      • Content Providers
      • Activities
        • Activity and Lifecycle
        • Saving state
        • Tasks and the back stack
      • Services
        • Services
        • Foreground Service
        • Bound Service
      • Dependency Injection
      • Workmanager
      • Fragment Findings*
      • Navigation findings*
      • Permissions Findings*
      • Room & Datastore findings*
    • Kotlin Topics
      • Nullables
      • Exceptions
      • Conditions and Loops
      • Arrays
      • Collections
      • Collection Functions
      • Class & Object
      • OOP Concepts
      • Scope Function
      • Visibility Modifiers
      • Generics
      • Kotlin Classes Types
        • Enums
        • Sealed Class
        • Data Classes
        • Nested and inner classes
        • Object expressions and declarations
      • Kotlin Functions Types
        • Functions
        • Extension functions
        • Higher-order functions and lambdas
      • Couroutines
      • Kotlin Flows
    • Interview Questions
      • Android Interview Questions
  • Products
    • Shabri
    • WedExhibit
  • About
  • More
    • Home
    • Institute Coaching Programs
    • Android curriculum
      • Android Topics
        • Notification
        • Broadcast & Broadcast Receiver
        • Content Providers
        • Activities
          • Activity and Lifecycle
          • Saving state
          • Tasks and the back stack
        • Services
          • Services
          • Foreground Service
          • Bound Service
        • Dependency Injection
        • Workmanager
        • Fragment Findings*
        • Navigation findings*
        • Permissions Findings*
        • Room & Datastore findings*
      • Kotlin Topics
        • Nullables
        • Exceptions
        • Conditions and Loops
        • Arrays
        • Collections
        • Collection Functions
        • Class & Object
        • OOP Concepts
        • Scope Function
        • Visibility Modifiers
        • Generics
        • Kotlin Classes Types
          • Enums
          • Sealed Class
          • Data Classes
          • Nested and inner classes
          • Object expressions and declarations
        • Kotlin Functions Types
          • Functions
          • Extension functions
          • Higher-order functions and lambdas
        • Couroutines
        • Kotlin Flows
      • Interview Questions
        • Android Interview Questions
    • Products
      • Shabri
      • WedExhibit
    • About

Dependency Injection↗

Basics
What is dependency injection?
Manual Dependency Injection
Without DI
With DI
How to implement?
Auto Dependency Injection
DI using HILT
Hilt modules
@inject vs @provides

Basics

Implementing dependency injection provides you with the following advantages:

  • Reusability of code

  • Ease of refactoring

  • Ease of testing

What is dependency injection?

Classes often require references to other classes. For example, a Car class might need a reference to an Engine class. These required classes are called dependencies, and in this example the Car class is dependent on having an instance of the Engine class to run.

There are three ways for a class to get an object it needs:

  1. The class constructs the dependency it needs. In the example above, Car would create and initialize its own instance of Engine.

  2. Grab it from somewhere else. Some Android APIs, such as Context getters and getSystemService(), work this way.

  3. Have it supplied as a parameter. The app can provide these dependencies when the class is constructed or pass them in to the functions that need each dependency. In the example above, the Car constructor would receive Engine as a parameter.

The third option is dependency injection! With this approach you take the dependencies of a class and provide them rather than having the class instance obtain them itself.

Manual Dependency Injection

Without DI

Here's an example. Without dependency injection, representing a Car that creates its own Engine dependency in code looks like this:

This is not an example of dependency injection because the Car class is constructing its own Engine. This can be problematic because:

  • Car and Engine are tightly coupled - an instance of Car uses one type of Engine. If the Car were to construct its own Engine, you would have to create two types of Car instead of just reusing the same Car for engines of type Gas and Electric.

  • The hard dependency on Engine makes testing more difficult.

With DI

What does the code look like with dependency injection? Instead of each instance of Car constructing its own Engine object on initialization, it receives an Engine object as a parameter in its constructor:

The benefits of this DI-based approach are:

  • Reusability of Car. You can pass in different implementations of Engine to Car. For example, you might define a new subclass of Engine called ElectricEngine that you want Car to use. If you use DI, all you need to do is pass in an instance of the updated ElectricEngine subclass, and Car still works without any further changes.

  • Easy testing of Car.

How to implement?

There are two major ways to do dependency injection in Android:

  • Constructor Injection. This is the way described above. You pass the dependencies of a class to its constructor.

  • Field Injection (or Setter Injection). Certain Android framework classes such as activities and fragments are instantiated by the system, so constructor injection is not possible. With field injection, dependencies are instantiated after the class is created. The code would look like this:

Auto Dependency Injection

In the previous example, you created, provided, and managed the dependencies of the different classes yourself, without relying on a library. This is called dependency injection by hand, or manual dependency injection.

In the Car example, there was only one dependency, but more dependencies and classes can make manual injection of dependencies more tedious. Manual dependency injection also presents several problems:

  • For big apps, taking all the dependencies and connecting them correctly can require a large amount of boilerplate code.

  • When you're not able to construct dependencies before passing them in — for example when using lazy initializations or scoping objects to flows of your app — you need to write and maintain a custom container (or graph of dependencies) that manages the lifetimes of your dependencies in memory.

Libraries to perform Dependency Injection

  • Dagger

Dagger is a popular dependency injection library for Java, Kotlin, and Android that is maintained by Google.

  • Hilt

Hilt is Jetpack's recommended library for dependency injection in Android. Hilt defines a standard way to do DI in your application by providing containers for every Android class in your project and managing their lifecycles automatically for you.Hilt is built on top of the popular DI library Dagger to benefit from the compile time correctness, runtime performance, scalability, and Android Studio support that Dagger provides.

DI using HILT

Steps to add HILT in your app:

  • First, add the hilt-android-gradle-plugin plugin to your project's root build.gradle file:

  id("com.google.dagger.hilt.android") version "2.44" apply false

  • Hilt uses Java 8 features. To enable Java 8 in your project, add the following to the app/build.gradle file:

    sourceCompatibility = JavaVersion.VERSION_1_8

Hilt application class

All apps that use Hilt must contain an Application class that is annotated with @HiltAndroidApp.

@HiltAndroidApp triggers Hilt's code generation, including a base class for your application that serves as the application-level dependency container.

This generated Hilt component is attached to the Application object's lifecycle and provides dependencies to it. Additionally, it is the parent component of the app, which means that other components can access the dependencies that it provides.

Inject Dependency into android class

Once Hilt is set up in your Application class and an application-level component is available, Hilt can provide dependencies to other Android classes that have the @AndroidEntryPoint annotation:

@Inject

@AndroidEntryPoint generates an individual Hilt component for each Android class in your project. These components can receive dependencies from their respective parent classes as described in Component hierarchy.

One way to provide binding information to Hilt is constructor injection. Use the @Inject annotation on the constructor of a class to tell Hilt how to provide instances of that class:

Hilt modules

Sometimes a type cannot be constructor-injected. This can happen for multiple reasons. For example, you cannot constructor-inject an interface. You also cannot constructor-inject a type that you do not own, such as a class from an external library. In these cases, you can provide Hilt with binding information by using Hilt modules.

A Hilt module is a class that is annotated with @Module. you must annotate Hilt modules with @InstallIn to tell Hilt which Android class each module will be used or installed in.

Consider the AnalyticsService example. If AnalyticsService is an interface, then you cannot constructor-inject it. Instead, provide Hilt with the binding information by creating an abstract function annotated with @Binds inside a Hilt module.

The @Binds annotation tells Hilt which implementation to use when it needs to provide an instance of an interface.

@inject vs @provides

Consider the previous example. If you don't directly own the AnalyticsService class, you can tell Hilt how to provide instances of this type by creating a function inside a Hilt module and annotating that function with @Provides.

The annotated function supplies the following information to Hilt:

  • The function return type tells Hilt what type the function provides instances of.

  • The function parameters tell Hilt the dependencies of the corresponding type.

  • The function body tells Hilt how to provide an instance of the corresponding type. Hilt executes the function body every time it needs to provide an instance of that type.

Note: This DI article is just a nutshell for detail information go to the official page

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

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

A brand by Jagrut Soni
Google Sites
Report abuse
Page details
Page updated
Google Sites
Report abuse