Если вы хотите использовать модель общего представления во фрагменте, вы должны использовать by activityViewModels()
вместо by viewModels()
.
Почему следующая строка работает, а by viewModels()
- нет?
ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
Потому что по умолчанию viewModels()
имеет значение аргумента ownerProducer
как { this }
. Чтобы лучше понять это, вот исходный код:
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
Как видите, это функция расширения для класса Fragment
. Это означает, что ViewModelStoreOwner
- это фрагмент . Как только фрагмент удаляется из стека, все модели представлений, которые он хранит в хранилище моделей представлений, исчезают.
Но если вы используете by activityViewModels()
, вы используете Activity
как владелец хранилища моделей представлений. Обратите внимание на использование requireActivity().viewModelStore
вместо ownerProducer().viewModelStore
, которое по умолчанию было Fragment
.
@MainThread
inline fun <reified VM : ViewModel> Fragment.activityViewModels(
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
В конце концов, createViewModelLazy
вызывает
ViewModelProvider(store, factory).get(viewModelClass.java)
, что эквивалентно создания модели представления вручную, используя
ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
Как исправить проблему?
Используйте by activityViewModels()
:
@AndroidEntryPoint
...
private val viewModel: SharedViewModel by activityViewModels()
Примечание: by activityViewModels()
и by viewModels()
- это просто реализации ленивой загрузки ViewModelProvider(...).get(...)
.