Dagger's Assisted Injection: Creating Objects with Runtime Data
Assisted Injection lets Dagger provide some dependencies while you supply the rest at runtime. It's for objects that need both graph-provided services and user-supplied data, like a specific ID. The footgun: you can't inject the object, only its factory.
WHY IT EXISTS Standard dependency injection with @Inject requires Dagger to know how to provide every single dependency for an object ahead of time. This model breaks when an object's creation depends on data that is only available at runtime, such as a user ID from navigation arguments or a configuration chosen by the user. Assisted Injection was created to bridge this gap.
THE MENTAL MODEL Think of Assisted Injection as a custom car factory. Dagger is the assembly line, providing the standard parts it always keeps in stock (the engine, chassis, wheels — your singleton services). You are the customer who specifies the custom, runtime details (the paint color, seat fabric — your user ID or config object). The @AssistedFactory is the factory manager who takes your custom order and tells the assembly line to build the car using both the standard parts and your special requests.
HOW IT WORKS You use three key annotations. First, mark the class's constructor with @AssistedInject. Second, for any parameters that you will provide at runtime, mark them with @Assisted. Dagger will provide all other unmarked parameters from its dependency graph. Third, define an interface annotated with @AssistedFactory. This factory must contain a single abstract method that returns your class and takes only the @Assisted parameters as arguments, in the exact same order as the constructor.
WHEN TO USE IT Use Assisted Injection when an object's creation depends on data that is not available in the Dagger graph. This is very common in Android for creating ViewModels that need repository dependencies from Dagger but also a specific ID passed through navigation arguments. It's also perfect for creating worker or service instances that require a specific, dynamic configuration to run.
WHEN NOT TO USE IT If Dagger can provide all of an object's constructor parameters, use a standard @Inject constructor. The factory pattern of Assisted Injection adds a layer of indirection that is unnecessary in that case. A critical limitation is that @AssistedInject types cannot be scoped (e.g., with @Singleton). If you need a single, shared instance of an object, it cannot have assisted parameters.
ONE CANONICAL EXAMPLE To create a UserDataViewModel needing a UserRepository from Dagger and a userId string at runtime, you'd annotate its constructor: class UserDataViewModel @AssistedInject constructor(val repository: UserRepository, @Assisted val userId: String). You would then define the factory: @AssistedFactory interface UserDataViewModelFactory { fun create(userId: String): UserDataViewModel }. In your UI controller, you inject the factory (@Inject lateinit var viewModelFactory: UserDataViewModelFactory) and then create the instance on demand via viewModelFactory.create("user-123").
Read the original → dagger.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.