I am using Android Studio - Dagger 2.35.1 (Not Hilt, just dagger), the ViewModel injection works fine using @Inject constructor() pattern, all is fun and games, but i am passing the id through a function to viewmodel which is something i do not like, so, now I am trying to implement an @Assisted param in ViewModel so the ViewModel receives the param during the construction, this param comes in the activity's intent.

After adding @AssistedInject constructor() pattern to ViewModel, now dagger complains:

[Dagger/MissingBinding DetailsViewModel cannot be provided without an @Inject constructor or an @Provides-annotated method

I have searched in all the questions and examples but nobody explains the full solution or why dagger sends that error, they just post sections of code, seems that dagger doesn't even know how to handle @AssistedInjection, at this point i am out of ideas.

class DetailsViewModel @AssistedInject constructor(
    application: Application,
    val repository: DetailsRepository,
    @Assisted val id: String,
) : BaseViewModel(application) {

    @AssistedFactory
    interface Factory { fun create(@Assisted id: String) : DetailsViewModel }

    companion object {
        @Suppress("UNCHECKED_CAST")
        fun factory(
            factory: Factory,
            id: String
        ) : ViewModelProvider.Factory {
            return object : ViewModelProvider.Factory {
                override fun <T : ViewModel> create(modelClass: Class<T>): T =
                    factory.create(id) as T
            }
        }
    }


class DetailsActivity : AppCompatActivity() {
    
    @Inject
    lateinit var viewModelFactory: DetailsViewModel.Factory

    private lateinit var viewModel: DetailsViewModel

     override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState)
        (application as MyApplication).appComponent.inject(this)

        val id = intent.getStringExtra("ID").orEmpty()

        viewModel = ViewModelProvider(this, DetailsViewModel.factory(
            viewModelFactory, id
        ))[DetailsViewModel::class.java]

}

ViewModelModule.java

@Module
public abstract class ViewModelModule {

   @Binds
   @IntoMap
   @ViewModelKey(DetailsViewModel.class)
   abstract ViewModel bindDetailsViewModel(DetailsViewModel viewModel);
}

AppComponent.java

@Singleton
@Component(modules = {AppModule.class, .class, ViewModelModule.class})
public interface AppComponent {

    void inject(DetailsActivity activity);

}
1

There are 1 best solutions below

0
Fred Porciúncula On

The ViewModelModule is the problem. You're trying to bind the ViewModel to a map but you can't because the ViewModel itself isn't part of the object graph, so you can't ask for it as a dependency since Dagger can't create it on its own — only the factory is in the graph, and you can use the factory to create your ViewModel. The error message is correctly telling you the ViewModel can't be provided as a dependency.

The setup is actually simpler: you can ditch the ViewModelModule and you should already be good to go. You can check this comment as a reference, and I'd recommend taking a look at my comment here as well as an idea to simplify the setup even further by using the viewModels() extension.