Действительно ли нам нужны viewModelFactories и viewmodelProviders при использовании Dagger? - PullRequest
0 голосов
/ 10 февраля 2020

Итак, я работал над примером проекта MVVM с использованием Dagger. У меня есть фабрика Viewmodel, которая выглядит следующим образом:

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)
        }
    }
}

Фабрика модуля Viewmodel

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

Я получил ViewModelModule:

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

Компонент, который идет например:

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

Модель представления, которая выглядит следующим образом:

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

Таким образом, я могу либо внедрить свою модель представления в свою деятельность, используя фабрику модели представления, например:

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

Или вообще не с фабрикой viewmodel, например:

@Inject
lateinit var takePicturesViewModel: TakePicturesViewModel

Оба способа работают, поэтому мне было интересно, какой из них правильный, если использование Dagger позволяет мне вводить модель представления без необходимости использования модели представления, есть ли хорошая причина для ее сохранения? Или мне просто нужно избавиться от этой модели представления?

Заранее благодарим за любой совет.

Привет

1 Ответ

2 голосов
/ 10 февраля 2020

Оба способа работают, поэтому мне было интересно, какой из них является правильным, если использование Dagger позволяет мне вводить модель представления без необходимости в модели представления модели, есть ли хорошая причина для ее сохранения? просто избавиться от этого viewmodelfactory?

Оба способа работают по-разному . Попробуйте повернуть экран с сохраненными данными в ViewModel, и вы увидите.

Dagger может создать ViewModel, который вы используете в этой обобщенной c ViewModelFactory. Эти модели представлений должны быть с незаданной областью, поэтому вы будете каждый раз создавать новую модель представления. Библиотека поддержки Android будет кэшировать эту ViewModel и повторно использовать ее после ротации, чтобы вы могли сохранить свои данные - заводской метод вызывается один раз, и когда-либо будет создаваться только одна ViewModel (за жизненный цикл). Вы сохраняете свои данные, и все ведет себя как ожидалось.

Если, с другой стороны, вы используете Dagger для непосредственного введения ViewModel, ни одно из вышеперечисленного не будет применяться. Как и любая другая зависимость, новая ViewModel будет внедрена при создании, что приведет к созданию ViewModel при каждом его использовании - вы будете не только использовать данные, хранящиеся в нем, вы не сможете делиться состоянием с фрагментами либо.

Конечно, вы могли бы применить область к ViewModel, но эта область должна быть дольше, чем экземпляр Activity (чтобы сохранять состояние между поворотами), но не дольше, чем экран виден. Таким образом, вы не можете ни включить его ни в действие, ни в жизненный цикл приложения. Вы можете заставить его работать, введя новую область видимости, но на этом этапе вам придется заново изобретать библиотеку ViewModel.


tl; dr Внедрите и используйте фабрику, иначе вы получите запутанную / неправильную реализацию ViewModel.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...