Assisted injection and runtime parameters
DI graphs provide known dependencies. Some values exist only at runtime: Worker parameters, navigation IDs, user-selected files, or a server-created session token.
Assisted factory
class ReportGenerator @AssistedInject constructor(
private val repository: ReportsRepository,
private val formatter: ReportFormatter,
@Assisted private val reportId: ReportId,
) {
@AssistedFactory
interface Factory {
fun create(reportId: ReportId): ReportGenerator
}
}
The graph injects stable services; caller supplies reportId. This preserves visible runtime input without placing it in a global mutable holder.
When not to use assisted injection
- ViewModel navigation arguments often arrive naturally through
SavedStateHandle. - Plain data objects should usually be constructed directly.
- If runtime value is durable application truth, repository should own/query it rather than pushing stale copies through factories.
- If every object has many assisted values, boundary design may be leaking presentation details inward.
Factory identity and validation
Validate runtime input at the boundary:
@JvmInline value class ReportId private constructor(val value: String) {
companion object { fun parse(raw: String): ReportId? = /* validate */ }
}
A factory should not accept an unvalidated arbitrary string when the constructed service requires a valid domain identifier.
Worker example mental model
Context and WorkerParameters are supplied by WorkManager (assisted). Repository/client dependencies come from Hilt. InputData carries small serializable work identifiers, not large object graphs.
Testing
Test the class directly with fake injected dependencies and explicit assisted values. Test factory wiring once; do not route every unit test through the full Hilt graph.
Runtime input describes this operation instance. Injected dependency describes how operations are performed. Keep that distinction visible.
Interview exercises
- Decide how a product ID reaches a ViewModel, Worker, and short-lived formatter.
- Replace a global “currentReportId” with assisted construction.
- Explain why large objects should not travel through Worker InputData.