Thread
#dagger
    blakelee

    blakelee

    1 year ago
    Is there way to inject viewmodels without having to create a factory for each one and also without hilt? I don’t need savedStateHandle or anything, I just want to use it like @Inject but have it survive configuration changes that a normal class won’t survive. I’ve seen several medium articles but I haven’t found a solution that can do it without a factory or hilt
    a

    allan.conda

    1 year ago
    @Binds
    @IntoMap @ViewModelClassKey(LoginViewModel::class)
    abstract fun bindViewModel(viewModel: SomeViewModel): ViewModel
    look for tutorials involving ViewModelClassKey
    a

    Ahmed Ibrahim

    1 year ago
    Yes, there is, since you don't use SavedStateHandle you can do it by using a Provider.
    @Inject
    lateinit var viewModelProvider: Provider<MyViewModel>
    
    private val myViewModel by viewModels {
        viewModelProvider.get()
    }
    blakelee

    blakelee

    1 year ago
    @allan.conda That just replaces the factory with a binds @Ahmed Ibrahim The viewModelProvider.get() doesn't seem to work. viewModels wants a ViewModelProvider.Factory
    a

    allan.conda

    1 year ago
    Yeah… you said no Factory or Hilt… That’s the plain Dagger solution
    blakelee

    blakelee

    1 year ago
    I was hoping there was a way to set it up with just @Inject like many of my other classes. I thought there was a way to do it similar to what Ahmed was suggesting, but I must be mistaken.
    a

    allan.conda

    1 year ago
    using Hilt is the closest to what you’re looking for with
    @ViewModelInject
    otherwise there’s no easy way since ViewModels are a corner case,
    a

    Ahmed Ibrahim

    1 year ago
    @blakelee Hey, sorry for providing an incomplete code, but yeah it's missing the ViewModelProvider.Factory as you said, but you can get around that by doing
    @Inject
        lateinit var viewModelProvider: Provider<MyViewModel>
    
        private val myViewModel: MyViewModel by viewModels {
            object: ViewModelProvider.Factory {
                override fun <T : ViewModel> create(modelClass: Class<T>): T {
                    @Suppress("UNCHECKED_CAST")
                    return viewModelProvider.get() as T
                }
            }
        }
    Now you can replace the ugly
    object: ViewModelProvider.Factory
    part by extracting it to an inline function to get a much more elegant version of the above code
    @Inject
        lateinit var viewModelProvider: Provider<ViewModel>
    
        private val myViewModel: ViewModel by viewModels {
           createSimpleViewModelFactory {        viewModelProvider.get() 
    }
        }
    blakelee

    blakelee

    1 year ago
    @Ahmed Ibrahim This seems like it could work. It's running on my device just fine. Just gotta make sure it really does handle config changes. Thanks!