Вызов модели просмотра Hilt-Dagger из фрагмента - PullRequest
0 голосов
/ 04 августа 2020

Я использую ViewModel для обновления заголовка на панели действий

SharedViewModel

class SharedViewModel @ViewModelInject constructor(
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    val title: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    val backButton: MutableLiveData<Boolean> by lazy {
        MutableLiveData<Boolean>()
    }
}

Наблюдатель MainActivity

@AndroidEntryPoint
...
sharedViewModel.title.observe(this, Observer {
    supportActionBar?.title = it
})

Используя приведенный ниже код кажется, создает новый экземпляр в Fragment (проверено в отладчике):

@AndroidEntryPoint
...
private val viewModel: SharedViewModel by viewModels()

Но, похоже, работает так

val viewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)

Ссылка на статью

Это должно быть так или я делаю что-то не так?

Спасибо!

1 Ответ

2 голосов
/ 04 августа 2020

Если вы хотите использовать модель общего представления во фрагменте, вы должны использовать 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(...).

...