Do we really need viewModelFactories and viewmodelProviders when using Dagger?

橙三吉。 提交于 2020-03-05 03:11:08

问题


So I was working on some sample MVVM project using Dagger. I have a viewmodel factory that goes like this:

class DaggerViewModelFactory @Inject constructor(private val viewModelsMap: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) :
    ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val creator = viewModelsMap[modelClass] ?:
        viewModelsMap.asIterable().firstOrNull {
            modelClass.isAssignableFrom(it.key)
        }?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
        return try {
            creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

A viewmodel factory module

@Module
abstract class ViewModelFactoryModule {
    @Binds
    abstract fun bindViewModelFactory(viewModelFactory: DaggerViewModelFactory): ViewModelProvider.Factory
}

I got a ViewModelModule:

@Module
abstract class MyViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(TakePicturesViewModel::class)
    abstract fun bindTakePictureViewModel(takePicturesViewModel: TakePicturesViewModel): ViewModel
}

A component that goes like this:

@PerActivity
@Subcomponent(modules = [ActivityModule::class, ViewModelFactoryModule::class, MyViewModelModule::class])
interface ActivityComponent {
    fun inject(mainActivity: MainActivity)
}

An a viewmodel that goes like this:

class TakePicturesViewModel @Inject constructor(app: Application): AndroidViewModel(app) {...

So I can either inject my viewmodel in my activity using a view model factory like this:

    @Inject
    lateinit var viewModelFactory: DaggerViewModelFactory
private lateinit var takePicturesViewModel: TakePicturesViewModel
.
.
.
    takePicturesViewModel = ViewModelProviders.of(this, viewModelFactory).get(TakePicturesViewModel::class.java)

Or with not viewmodel factory at all, like this:

@Inject
lateinit var takePicturesViewModel: TakePicturesViewModel

Both ways work, so I was wondering which one is the right way to work, if using Dagger allows me to inject a viewmodel without needing a viewmodelfactory, is there a good reason to keep it?, or should I just get rid of this viewmodelfactory?

Thanks in advance for any advice.

Greetings


回答1:


Both ways work, so I was wondering which one is the right way to work, if using Dagger allows me to inject a viewmodel without needing a viewmodelfactory, is there a good reason to keep it?, or should I just get rid of this viewmodelfactory?

Both ways work differently. Try rotating your screen with stored data in your ViewModel and you'll see.

Dagger can create the ViewModel, which is what you make use of in that generic ViewModelFactory. Those view models should be unscoped, thus you'll be creating a new ViewModel every single time. The Android support library will cache that ViewModel and reuse it after rotation so that you can keep your data—the factory method gets called once and there will only ever be one ViewModel created (per lifecycle). You keep your data and everything behaves as expected.

If on the other hand you use Dagger to inject your ViewModel directly none of the above will apply. Like any other dependency, a new ViewModel will be injected on creation, leading to a ViewModel being created every single time it is used—you'll not only use the data stored in it, you won't be able to share state with fragments either.

Of course you could apply a scope to the ViewModel, but that scope should be longer lived than the Activity instance (to keep state between rotations), but no longer lived than the screen is visible. So you can neither scope it to the activity nor to the application lifecycle. You can get it to work by introducing a new scope in-between, but at this point you'd be reinventing the ViewModel library.


tl;dr Inject and use the factory or you'll get a confusing/wrong ViewModel implementation.



来源:https://stackoverflow.com/questions/60141954/do-we-really-need-viewmodelfactories-and-viewmodelproviders-when-using-dagger

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!