Вы смешиваете как минимум 4 разные вещи здесь.
Возможно, проблема в том, что Dagger создает новый экземпляр моей модели представления каждый раз, когда мой фрагмент (и активность контейнера)воссоздан.
Вы объявляете viewModel
введенным в поле при вставке фрагмента (поскольку вы добавили аннотацию @Inject
к свойству ...)
@Inject lateinit var viewModelFactory : ViewModelFactory
Это означает, что Dagger будет вводить поле, когда вы звоните AndroidInjection.inject(..)
.Поскольку вы используете инъекцию конструктора (@Inject
в конструктор MedicationsViewModel
), Dagger каждый раз будет создавать новый объект (вы не охватывали класс), но вы никогда не используете объектВ любом случае, потому что ...
Сразу после , когда произошло, вы переопределяете поле с помощью viewModel из ViewModelFactory
viewModel = ViewModelProviders.of(this, viewModelFactory).get(MedicationsViewModel::class.java)
Поскольку ViewModelFactory использует@Binds @IntoMap @Singleton bindMedicationsViewModel
этот должен повторно использовать один и тот же объект и иметь @Singleton
область видимости.Вы не поделились своей реализацией, поэтому, если это не тот же объект, вы можете неправильно обработать свой @Singleton
компонент.
Больше проблем ...
Но яМысль, аннотирующая мою ViewModelFactory с областью действия @Singleton, исправила бы это.
Обычно следует помещать области видимости в класс , а не в привязку.
@Singleton // scope the class!
class MedicationsViewModel @Inject constructor()
Это потому, что обычно это детали реализации того, что есть у чего-то.Но в любом случае вам не следует использовать @Singleton
здесь вообще, так как вы пытаетесь использовать ViewModel thingy .Если вы хотите использовать @Singleton
для вашей ViewModel, тогда вам не нужен весь бит ViewModelProviders
.Как вы можете видеть, это приведет только к ошибкам и путанице, поскольку оба имеют разные области действия и обрабатываются по-разному.
Лучшая настройка
Предполагая, что вы хотите использовать ViewModels, вы делаете , а не сфокусировать ViewModel на Dagger.Вы позволяете компонентам Android Arch обрабатывать вещи.Вы используете Dagger только для того, чтобы удалить шаблон создания объекта, чтобы ViewModel.Factory
мог легко создать новую ViewModel при необходимости .Вы делаете это, привязывая ViewModel к коллекции, которая передается на вашу фабрику (карта с <Class, Provider<ViewModel>>
). Вызов provider.get()
всегда будет создавать новый объект, как и ожидалось.В конце концов, жизненный цикл обрабатывается компонентами арки.
@Binds
@IntoMap
@ViewModelKey(MedicationsViewModel.class) // no scope here!
abstract ViewModel bindMedicationsViewModel(MedicationsViewModel viewModel);
// neither here!
class MedicationsViewModel @Inject constructor()
После установки ViewModelStoreOwner (ViewModelProviders.of(this)
) будет управлять жизненным циклом ViewModels и решать, когда повторно использовать или воссоздать модель.Если вы введете область видимости Dagger в ViewModel, она либо ничего не сделает (если область имеет более короткий срок действия), либо может привести к ошибкам или неожиданному поведению (при использовании @Singleton
или более долгоживущих)
ДалееViewModel.Factory
также должен быть с незаданной областью
@Binds // no scope here either!
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory);
Это сделано для того, чтобы вы также могли добавлять ViewModel в ваши компоненты с фрагментами / действиями и позволять вам вводить классы, которые также не являются одноэлементными.Это значительно улучшит гибкость.Область видимости в классе также не будет иметь никаких преимуществ, поскольку ViewModels не хранится там во время изменений конфигурации и не содержит никакого состояния.
И последнее, но не менее важное: вы этого не делаетевведите поле с помощью Dagger, но вы используете ViewModelProviders
для его инициализации.Хотя он не должен делать ничего, поскольку вы переопределяете его снова несколько мгновений спустя, он все еще является неприятным запахом и приведет только к путанице.
// in your fragment / acitvity
lateinit var viewModelFactory : ViewModelFactory // no @Inject for the viewmodel here!
// it will be assigned in onCreate!
viewModel = ViewModelProviders.of(this, viewModelFactory).get(MedicationsViewModel::class.java)
Надеюсь, это кое-что прояснит!