Bird
Raised Fist0
Android Kotlinmobile~20 mins

Dependency injection with Hilt in depth in Android Kotlin - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Hilt Dependency Injection Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ component_behavior
intermediate
2:00remaining
What is the output when injecting a singleton with Hilt?
Consider a Hilt module that provides a singleton instance of a Repository class. If two different Android components inject this Repository, what will be the behavior of the injected instances?
Android Kotlin
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
    @Provides
    @Singleton
    fun provideRepository(): Repository = Repository()
}

class Repository {
    val id = System.identityHashCode(this)
}

@AndroidEntryPoint
class ActivityA : AppCompatActivity() {
    @Inject lateinit var repository: Repository
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        println("ActivityA Repository ID: ${repository.id}")
    }
}

@AndroidEntryPoint
class ActivityB : AppCompatActivity() {
    @Inject lateinit var repository: Repository
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        println("ActivityB Repository ID: ${repository.id}")
    }
}
AEach Activity receives a new Repository instance with different IDs.
BBoth ActivityA and ActivityB receive the same Repository instance with identical IDs.
CInjection fails because Repository is not annotated with @Inject constructor.
DBoth Activities receive null for Repository because it is not scoped to activities.
Attempts:
2 left
💡 Hint
Think about the @Singleton annotation and the component scope it is installed in.
📝 Syntax
intermediate
1:30remaining
Which Hilt annotation is missing to enable constructor injection?
Given the following Kotlin class, which annotation must be added to enable Hilt to inject it via constructor injection?
Android Kotlin
class NetworkClient(private val baseUrl: String) {
    fun fetchData(): String = "Data from $baseUrl"
}
A@Inject constructor(private val baseUrl: String)
B@Provides fun NetworkClient()
C@Singleton class NetworkClient(private val baseUrl: String)
D@Module class NetworkClient(private val baseUrl: String)
Attempts:
2 left
💡 Hint
Constructor injection requires a specific annotation on the constructor.
🔧 Debug
advanced
2:30remaining
Why does this Hilt injection cause a runtime error?
Examine the following code snippet. What is the cause of the runtime error when injecting UserRepository into ViewModel?
Android Kotlin
@HiltViewModel
class UserViewModel @Inject constructor(
    private val userRepository: UserRepository
) : ViewModel()

class UserRepository @Inject constructor(
    private val apiService: ApiService
)

@Module
@InstallIn(ActivityComponent::class)
object NetworkModule {
    @Provides
    fun provideApiService(): ApiService = ApiService()
}
AApiService class is missing @Inject constructor causing provider failure.
BUserRepository is missing @Singleton annotation causing multiple instances and conflict.
CApiService is provided in ActivityComponent scope but UserViewModel is in ViewModelComponent, causing a scope mismatch.
DUserViewModel lacks @Singleton annotation causing injection failure.
Attempts:
2 left
💡 Hint
Check the component scopes where dependencies are provided and injected.
🧠 Conceptual
advanced
1:40remaining
What is the role of @InstallIn in Hilt modules?
Why is the @InstallIn annotation required on a Hilt module, and what does it control?
A@InstallIn is used to declare a module as a replacement for another module.
B@InstallIn marks a module as injectable via constructor injection.
C@InstallIn automatically generates a singleton instance of all provided dependencies.
D@InstallIn specifies the Hilt component(s) where the module's bindings are available, controlling the lifecycle and scope of provided dependencies.
Attempts:
2 left
💡 Hint
Think about how Hilt knows where to use the module's bindings.
❓ state_output
expert
3:00remaining
What is the output of this Hilt assisted injection example?
Given the following code using Hilt's AssistedInject, what will be printed when creating a UserViewModel with userId = 42?
Android Kotlin
class UserRepository @Inject constructor()

class UserViewModel @AssistedInject constructor(
    private val userRepository: UserRepository,
    @Assisted private val userId: Int
) {
    fun printUser() = println("UserViewModel with userId: $userId and repo: $userRepository")
}

@AssistedFactory
interface UserViewModelFactory {
    fun create(userId: Int): UserViewModel
}

fun main() {
    // Simulate assisted injection factory usage
    val repo = UserRepository()
    val factory = object : UserViewModelFactory {
        override fun create(userId: Int) = UserViewModel(repo, userId)
    }
    val vm = factory.create(42)
    vm.printUser()
}
AUserViewModel with userId: 42 and repo: UserRepository@<hashcode>
BUserViewModel with userId: 0 and repo: UserRepository@<hashcode>
CCompilation error due to missing @Inject on UserViewModel constructor
DRuntime error because AssistedInject is not supported without Hilt setup
Attempts:
2 left
💡 Hint
Assisted injection allows passing runtime parameters while injecting other dependencies.

Practice

(1/5)
1. What is the primary purpose of using @Module and @Provides annotations in Hilt?
easy
A. To tell Hilt how to create and supply dependencies
B. To mark an Android Activity for injection
C. To automatically generate UI components
D. To define navigation between screens

Solution

  1. Step 1: Understand the role of @Module

    @Module is used to group methods that provide dependencies to Hilt.
  2. Step 2: Understand the role of @Provides

    @Provides annotates methods inside a module to tell Hilt how to create specific dependencies.
  3. Final Answer:

    To tell Hilt how to create and supply dependencies -> Option A
  4. Quick Check:

    @Module + @Provides = supply dependencies [OK]
Hint: Remember: @Module groups, @Provides creates dependencies [OK]
Common Mistakes:
  • Confusing @Module with @AndroidEntryPoint
  • Thinking @Provides creates UI elements
  • Assuming @Module is for navigation
2. Which of the following is the correct way to inject a dependency into an Android Activity using Hilt?
easy
A. Annotate the Activity with @AndroidEntryPoint and use @Inject on the field
B. Use @Module on the Activity class
C. Call Hilt.inject(this) inside onCreate()
D. Add @Provides on the Activity constructor

Solution

  1. Step 1: Identify how to enable injection in Activity

    Hilt requires the Activity to be annotated with @AndroidEntryPoint to generate necessary code.
  2. Step 2: Inject dependencies with @Inject

    Fields or constructor parameters annotated with @Inject receive dependencies automatically.
  3. Final Answer:

    Annotate the Activity with @AndroidEntryPoint and use @Inject on the field -> Option A
  4. Quick Check:

    @AndroidEntryPoint + @Inject field = inject Activity dependency [OK]
Hint: Use @AndroidEntryPoint on Activity, then @Inject fields [OK]
Common Mistakes:
  • Trying to use @Module on Activity
  • Calling non-existent Hilt.inject() method
  • Adding @Provides on constructors
3. Given the following code snippet, what will be the output when MyViewModel is injected?
class MyRepository @Inject constructor() {
    fun getData() = "Data from repository"
}

@HiltViewModel
class MyViewModel @Inject constructor(private val repo: MyRepository) : ViewModel() {
    fun fetch() = repo.getData()
}
medium
A. "fetch() method not found"
B. NullPointerException at runtime
C. Compilation error due to missing @Provides
D. "Data from repository"

Solution

  1. Step 1: Understand constructor injection in MyRepository

    MyRepository has an @Inject constructor, so Hilt can create it automatically.
  2. Step 2: MyViewModel receives MyRepository via constructor injection

    Hilt injects MyRepository instance into MyViewModel, so calling fetch() returns repo.getData() string.
  3. Final Answer:

    "Data from repository" -> Option D
  4. Quick Check:

    Constructor injection returns data string [OK]
Hint: If constructor has @Inject, Hilt creates instance automatically [OK]
Common Mistakes:
  • Assuming @Provides is always needed
  • Expecting runtime null errors with constructor injection
  • Confusing method names in ViewModel
4. Identify the error in this Hilt module code:
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    fun provideHttpClient(): OkHttpClient {
        return OkHttpClient()
    }

    @Provides
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .client(client)
            .baseUrl("https://api.example.com")
            .build()
    }
}
medium
A. Missing @Singleton annotation on provider methods
B. Retrofit.Builder() requires a converter factory
C. OkHttpClient cannot be provided without parameters
D. NetworkModule should be a class, not an object

Solution

  1. Step 1: Review Retrofit.Builder usage

    Retrofit requires a converter factory (like GsonConverterFactory) to parse responses; missing here causes runtime error.
  2. Step 2: Check other options for correctness

    @Singleton is optional but recommended; object is valid for modules; OkHttpClient can be created without parameters.
  3. Final Answer:

    Retrofit.Builder() requires a converter factory -> Option B
  4. Quick Check:

    Retrofit needs converter factory to build properly [OK]
Hint: Retrofit always needs a converter factory to avoid errors [OK]
Common Mistakes:
  • Thinking @Singleton is mandatory for all providers
  • Confusing object vs class for modules
  • Assuming OkHttpClient needs parameters
5. You want to inject two different implementations of an interface Logger using Hilt. How can you distinguish them during injection?
hard
A. Use @Singleton on one implementation and omit on the other
B. Create two separate modules with the same provider method name
C. Use @Named qualifiers with different names on provider methods and injection points
D. Inject both implementations into a list automatically

Solution

  1. Step 1: Understand multiple implementations injection

    When multiple bindings exist for the same type, Hilt requires qualifiers to distinguish them.
  2. Step 2: Use @Named qualifiers

    Annotate provider methods and injection points with @Named("name") to specify which implementation to inject.
  3. Final Answer:

    Use @Named qualifiers with different names on provider methods and injection points -> Option C
  4. Quick Check:

    Multiple implementations need @Named qualifiers [OK]
Hint: Use @Named("tag") to differentiate implementations [OK]
Common Mistakes:
  • Assuming module separation alone distinguishes implementations
  • Using @Singleton to differentiate implementations
  • Expecting automatic list injection without setup
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard