# Ultimate Guide to Dependency Injection in Android — Part 2. Manual DI and Practice

In this article, I’m going to reference some points from the [first article](https://devblogs.dashwave.io/ultimate-guide-to-dependency-injection-in-android-part-1-di-and-its-benefits). Read it first if you want to have the complete picture.

In software development, dependency injection is a technique that allows you to decouple components and improve the testability of your code. Dependency injection can be done manually or through a framework. In this article, we’ll focus on manual dependency injection in Kotlin.

![](https://miro.medium.com/v2/resize:fit:700/0*qUn_fTEMaCdp492s.jpg align="center")

## **Manual Dependency Injection**

Manual dependency injection is the process of manually creating and managing dependencies in your code. In this approach, you define the dependencies in a container or a factory and then inject them into the classes that need them.

## **Diving into manual DI**

Consider the following code snippet that initializes the `ShopViewModel` class inside an `Activity`.

```kotlin
class ShopActivity: Activity() {

private lateinit var shopViewModel: ShopViewModel

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)

       val db = Room.databaseBuilder(
           applicationContext,
           MyDatabase::class.java, "my-database-name").build()

       val localDataSource = ShopLocalDataSource(db)
       val remoteDataSource = ShopRemoteDataSource()

       val shopRepository = ShopRepository(localDataSource, remoteDataSource)

       //used in multiple places in the app
       shopViewModel = ShopViewModel(shopRepository) 
   }
}
```

The `ShopActivity` class initializes the `ShopViewModel` class by creating instances of `Room`, `ShopLocalDataSource`, `ShopRemoteDataSource`, `ShopRepository`, and finally `ShopViewModel`. This approach tightly couples the `ShopActivity` class with the `ShopViewModel` class, making it difficult to test and reuse the `ShopViewModel` class in other parts of the application.

There are several problems with this code:

1. In order to create `ShopViewModel` we need to initialize all of the other dependencies first in sequential order.
    
2. In case we wanted to use the `ShopViewModel` in other parts of our application — there’s no way to do that except for creating another instance of `ShopViewModel` . Considering that `ShopViewModel` uses a `ShopRepository` — we really want should avoid creating multiple instances of our data source. We can use an `object` or a singleton pattern, but there’s an easier way to do that with DI.
    
3. The amount of boilerplate code that needs to be written to create a single dependency.
    

Let’s see how we can address these problems.

![Photo by Dominik Lückmann on Unsplash](https://miro.medium.com/v2/resize:fit:700/0*U03juU9lKB1Qvwhs align="center")

## **Step 1: Abstract away the creation of dependencies**

The first step is to delegate the creation of our dependencies to a separate class. We can do this by building a container.

```kotlin
class AppContainer {
    private val db =
        Room.databaseBuilder(applicationContext, MyDatabase::class.java, "my-database-name").build()

    private val localDataSource = ShopLocalDataSource(db)
    private val remoteDataSource = ShopRemoteDataSource()

    private val shopRepository = ShopRepository(localDataSource, remoteDataSource)

    val shopViewModel = ShopViewModel(shopRepository)
}
```

As you can see, only the `shopViewModel` is exposed for access. So far, we only need access only to `shopViewModel`, so we can make the rest of the dependencies `private`.

## **Step 2: Initialize the container in the Application class**

An `Application` class in our case is the [Android Application](https://developer.android.com/reference/android/app/Application). In the `MyApplication` class, we initialize the `AppContainer` and store it in a public `val`property. This gives us two benefits:

1. Our `AppContainer` is now available anywhere in our app.
    
2. Since we only have one `Application` class instance per our application by default — this ensures that we also have a single instance of the `AppContainer` as well.
    

```kotlin
class MyApplication : Application() {
   val appContainer = AppContainer()
}
```

## **Step 3: Glue it all together**

Finally, we can inject our `ShopViewModel` via our newly created Container. First, let’s declare our `ShopViewModel` variable as `lateinit`. This gives our compiler a guarantee that this variable will be initialized later on. After that, we can get the instance of our `ShopViewModel` that was already created for us by going referencing `MyApplication -> AppContainer -> ShopViewModel`. Our `ShopViewModel` is already created for us the moment our Application is created, so all we need to do is reference it.

```kotlin
class ShopActivity: Activity() {

  private lateinit var shopViewModel: ShopViewModel

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
         shopViewModel = (applicationContext as MyApplication).appContainer.shopViewModel
  }
}
```

![](https://miro.medium.com/v2/resize:fit:700/0*8R-MF1xb4jDvg_iW align="center")

## **Field injection**

But wait, you might say. This looks different from the constructor injection that we were doing [in the previous article](https://medium.com/@nikolaymiroshnychenko/the-ultimate-guide-to-dependency-injection-in-android-what-is-di-and-its-benefits-part-1-2e0d5fed242d). And you’re right. This type of injection is called ***field injection***.

We can’t do constructor injection in our Activities for one simple reason. We can’t explicitly create Activities or other Android components for this matter like Services, Broadcast Receiver, etc. The system creates these components for us, and therefore we can’t perform constructor injection with them. So if you have any classes that you’re not creating yourself — the only way you can use DI with them is by field injection.

## **Injecting a Different Instance Every Time**

In some cases, you may need a different instance of a dependency every time it’s used. For example, let’s imagine that we need a different instance of `ShopViewModel` in different parts of the app. In this case, you can use a Factory to create a new instance of the dependency every time it's needed. Let’s see how we can do that:

```kotlin
interface Factory<T> {
   fun create(): T
}

class ShopViewModelFactory(private val shopRepository: ShopRepository) : Factory<ShopViewModel> {
   override fun create(): ShopViewModel {
       return ShopViewModel(shopRepository)
   }
}

class AppContainer {
   private val shopRepository = ShopRepository(localDataSource, remoteDataSource)
   val shopViewModelFactory = ShopViewModelFactory(shopRepository)
}
```

First, we define a generic Factory interface. Then we inherit from this interface in our `ShopViewModelFactory` class. Each time the `create()` method is called — we will get a different instance of `ShopViewModel`. Now let’s inject this into our `ShopActivity`:

```kotlin
class ShopActivity: Activity() {

  private lateinit var shopViewModel: ShopViewModel

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
         shopViewModel = (applicationContext as MyApplication).appContainer.shopViewModelFactory.create()
  }
}
```

This code is almost identical to our previous example, except that now we’re exposing the Factory that produces our `ShopViewModel` instead of creating the `ShopViewModel` ourselves. With this setup, we will be able to get a new instance of `ShopViewModel` each time.

![](https://miro.medium.com/v2/resize:fit:700/0*zyMII7q7536fv1XZ align="left")

## **Scoped Dependencies**

In some cases, you may need a dependency to be scoped to a particular part of the app. By *scoped* I mean that it should “live” as long as the component in which it is located “lives”. For example, take a look at the picture below:

![](https://miro.medium.com/v2/resize:fit:700/1*4SaoHBV1LHzYQ2O_fChzHQ.png align="left")

Let’s imagine we’re configuring some product in our Shop flow. The configuration of that product needs to exist as long as our `ShopActivity` exists — even when we navigate through our Fragments back and forth. But it doesn’t need to exist longer than `ShopActivity`— because it won’t be relevant in other parts of the app.

Let’s imagine that the configuration of our product will be stored in something like this:

```kotlin
data class ConfiguredItem(val color: String, val price: Int)
```

In order for the `ShopActivity` to have scoped dependencies. — the first thing that we need to do is to create a container specifically for the `ShopActivity`. This container should live only as long as the `ShopActivity` lives. Let’s define a `ShopContainer`:

```kotlin
class ShopContainer(shopRepository: ShopRepository) {
   val configuredItem = ConfiguredItem("", 0)
   //shopRepository used for some other dependencies
}
```

In the `ShopContainer` class, we define a `configuredItem` property that stores the `ConfiguredItem` instance. Since `ConfiguredItem` is only needed inside our Shop flow it makes sense to put it inside a container that’s scoped to this flow. Let’s also imagine that `ShopContainer` takes `ShopRepository` as a dependency for some other dependencies. Now let’s proceed to enclose our `ShopContainer`:

```kotlin
class AppContainer {
   val shopRepository = ShopRepository(localDataSource, remoteDataSource)
   var shopContainer: ShopContainer? = null
}
```

In the `AppContainer` class, we define a `shopContainer` property that stores the `ShopContainer` instance. By using a nullable `var` property, we can create and destroy the `ShopContainer` instance as needed. Now let’s see how we can use our scoped `ConfiguredItem` inside `ShopActivity`:

```kotlin
class ShopActivity : Activity() {
    private lateinit var configuredItem: ConfiguredItem
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val appContainer = (application as MyApplication).appContainer
        appContainer.shopContainer = ShopContainer(appContainer.shopRepository)
        configuredItem = appContainer.shopContainer!!.configuredItem
    }

    override fun onDestroy() {
        super.onDestroy()
        (application as MyApplication).appContainer.shopContainer = null
    }
}
```

First, inside `onCreate()`we build the `AppContainer`. Then, we initialize the `ShopContainer` inside `AppContainer` by passing the `ShopRepository` dependency from the latter. After that, we initialize the `ConfiguredItem` instance that needs to live as long as the `ShopActivity` does. Finally, we need to free up the memory that was allocated to the `ShopContainer` when `ShopActivity` is destroyed. We do this by simply overriding `onDestroy()` and assigning a null value to our `ShopContainer` variable inside `AppContainer`.

And that’s it. Now you have a dependency that’s scoped exclusively to the Shop flow.

![](https://miro.medium.com/v2/resize:fit:700/0*ZjTa-UlCiOTw31tv align="left")

## **Advantages vs disadvantages of manual DI.**

Manual dependency injection has several advantages and disadvantages.

**Advantages:**

* Total control and understanding over everything you write.
    

**Disadvantages:**

* Lots of boilerplate code.
    
* You have to manage the lifecycle of dependencies yourself.
    

## **Dependency Injection Best Practices**

To make the most of dependency injection, there are some best practices you should follow.

1. **Expose the Policy, Hide the Detail**
    

Let’s look at our good ol’ `Computer` class:

```kotlin
interface IProcessor {
   fun process()
}

class Computer(private val processor: IProcessor) {
    fun compute() {
        processor.process()
    }
}
```

In the `Computer` class, we define a `compute()` method that uses an instance of `IProcessor` to compute something. By using an interface, we can easily swap out the implementation of `IProcessor` whenever we need to without changing the `Computer` class.

**2\. Follow the Single Responsibility Principle (SRP)**

The Single Responsibility Principle (SRP) states that a class should have only one reason to change. In the context of dependency injection, this means you have to define dependencies in a separate class that has its own responsibility.

Let’s look at this piece of code:

```kotlin
class UserService(private val databaseUrl: String) {
   fun getUser(id: Int): User? {
       val databaseConnection = DatabaseConnection(databaseUrl)
       val userRepository = UserRepository(databaseConnection)
       return userRepository.getUserById(id)
   }
}
```

Can you tell how it’s violating the SRP? The main responsibility of this class should get getting the user. However, in the example above it’s also responsible for creating the dependencies that it needs. To remedy this, we should pass `UserService` all of the dependencies that it needs without it having to create them itself. Here is the proper implementation:

```kotlin
class UserService(private val userRepository: UserRepository) {
   fun getUser(id: Int): User? {
       return userRepository.getUserById(id)
   }
}
```

This follows the SRP by defining the dependency in a separate class.

**3\. Use DI libraries**

If you’re writing a production app — it’s much better to use a library than having to use manual DI. DI libraries were written and are supported by very smart people. They have lots of features that can save you a lot of time and headache. There are many DI libraries for Android and Kotlin, but the most popular are — [Dagger2](https://github.com/google/dagger), [Hilt](https://dagger.dev/hilt/), [Koin](https://insert-koin.io/), and [Kodein](https://github.com/kosi-libs/Kodein).

## **Recap**

Dependency injection is a technique that allows you to decouple components and improve the testability of your code. In this article, we covered manual dependency injection in Kotlin and Android, which involves defining dependencies in a container or a factory and injecting them into the classes that need them. We also covered best practices such as exposing the policy and hiding the detail, following the SRP, and using DI libraries. By using these techniques, you can make your code more modular, testable, and maintainable.

**Sources**:

Android Manual DI training — [https://developer.android.com/training/dependency-injection/manual](https://developer.android.com/training/dependency-injection/manual)

### **Thanks for reading! If you found this post valuable, please recommend it (the little handclap) so it can reach others.**
