Sobes.tech
Middle

What is the purpose of dependency injection in Android applications?

sobes.tech AI

Answer from AI

Dependency Injection (DI) is used in Android applications to decompose code, improve testability, and facilitate refactoring. It allows components to receive dependencies from external sources rather than creating them themselves.

The main goals of using DI in Android:

  • Decoupling: Components become less tightly coupled. Changing one dependency does not require modifications in the component that uses this dependency.
  • Testability: Easy to substitute test implementations of dependencies (mocks, fakes) when writing unit tests.
  • Lifecycle management: DI frameworks can manage the creation and destruction of objects, ensuring proper lifecycle handling for dependencies, which is especially relevant in Android with its specific lifecycle of Activities, Fragments, etc.
  • Reusability: Dependencies can be easily reused by different components of the application.
  • Code simplification: Code becomes cleaner and more understandable, as there is no need to manually create and pass dependencies through constructors or setters.

Examples of DI frameworks in Android: Hilt (recommended by Google), Dagger, Koin.

Example (pseudo-code without DI):

// Class that creates a dependency internally
class UserRepository {
    private val apiService = ApiService() // Internal creation of dependency

    fun getUser(id: Int): User {
        return apiService.fetchUser(id)
    }
}

class ApiService {
    fun fetchUser(id: Int): User {
        // Logic to fetch data
        return User(id, "John Doe")
    }
}

data class User(val id: Int, val name: String)

Example (pseudo-code with DI):

// Class that receives dependency via constructor
class UserRepository(private val apiService: ApiService) {

    fun getUser(id: Int): User {
        return apiService.fetchUser(id)
    }
}

class ApiService {
    fun fetchUser(id: Int): User {
        // Logic to fetch data
        return User(id, "Jane Doe")
    }
}

data class User(val id: Int, val name: String)

// Somewhere in the code, where DI is configured:
// val apiService = ApiService()
// val userRepository = UserRepository(apiService)

In the last example, UserRepository does not know how to create ApiService; it simply receives it from outside. This makes it easier to substitute ApiService with a test version during testing of UserRepository.

What is the purpose of dependency injection in… - sobes.tech