Как Android ViewModel гарантирует, что он должен связываться с той же деятельностью или фрагментом (в случае поворота экрана)? - PullRequest
0 голосов
/ 03 февраля 2020

Я сейчас работаю над Android ViewModel. Один вопрос постоянно возникает в моей голове. Как ViewModel обеспечивает повторное связывание с той же операцией или фрагментом после поворота экрана, несмотря на то, что мы создаем новый объект в onCreate или onCreateView?

У кого-нибудь есть правильный ответ на этот вопрос, пожалуйста, дайте мне знать. Я пытался найти решение во многих уроках.

Заранее спасибо!

1 Ответ

1 голос
/ 03 февраля 2020

Когда создается новый экземпляр ViewModelProvider, первый параметр - activity.getViewModelStore() и, согласно документации,

Возвращает {@link ViewModelStore}, связанный с этим действием

Переопределение этот метод больше не поддерживается, и этот метод будет установлен final в будущей версии ComponentActivity. @return a {@code ViewModelStore} @throws IllegalStateException, если вызывается до того, как Activity прикреплена к экземпляру приложения, т. е. перед onCreate ()

возвращает объект ViewModelStore. Так что же такое ViewModelStore?

/**
 * Class to store {@code ViewModels}.
 * <p>
 * An instance of {@code ViewModelStore} must be retained through configuration changes:
 * if an owner of this {@code ViewModelStore} is destroyed and recreated due to configuration
 * changes, new instance of an owner should still have the same old instance of
 * {@code ViewModelStore}.
 * <p>
 * If an owner of this {@code ViewModelStore} is destroyed and is not going to be recreated,
 * then it should call {@link #clear()} on this {@code ViewModelStore}, so {@code ViewModels} would
 * be notified that they are no longer used.
 * <p>
 * Use {@link ViewModelStoreOwner#getViewModelStore()} to retrieve a {@code ViewModelStore} for
 * activities and fragments.
 */
 public class ViewModelStore {

 private final HashMap<String, ViewModel> mMap = new HashMap<>();

 final void put(String key, ViewModel viewModel) {
    ViewModel oldViewModel = mMap.put(key, viewModel);
    if (oldViewModel != null) {
        oldViewModel.onCleared();
    }
 }

 final ViewModel get(String key) {
    return mMap.get(key);
 }

 Set<String> keys() {
    return new HashSet<>(mMap.keySet());
 }

 /**
  *  Clears internal storage and notifies ViewModels that they are no longer used.
  */
 public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
  }
}

По сути, это класс с HashMap, ключ которого равен DEFAULT_KEY + “:” + canonicalName, где DEFAULT_KEY равен androidx.lifecycle.ViewModelProvider.DefaultKey, а значение равно ViewModel

Это означает, что каждая активность и фрагмент имеют ViewModelStore, который сохраняет все объявленные ViewModels в активности или фрагменте соответственно.

Но как ViewModelStore переживает изменение ориентации?

В документации ViewModelStore определено, что

, если владелец этого {@code ViewModelStore} уничтожен и воссоздан из-за изменений конфигурации *, новый экземпляр владельца все еще должен иметь тот же старый экземпляр * {@code ViewModelStore}.

Так что ответственность за действия - сохранить ViewModelStore во время смены ориентации.

Если мы go вернемся к activity.getViewModelStore() реализации, тогда мы найдем ответ.

if (mViewModelStore == null) {
    NonConfigurationInstances nc =
        (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null) {
        // Restore the ViewModelStore from NonConfigurationInstances
        mViewModelStore = nc.viewModelStore;
    }
    if (mViewModelStore == null) {
        mViewModelStore = new ViewModelStore();
    }
}

Деятельность делает это с помощью чего-то под названием NonConfigurationInstances. NonConfigurationInstances является окончательным c конечным классом

static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

Таким образом, он сначала проверяет, есть ли уже viewmodelstore, сохраненный в NonConfigurationInstances, если нет, он создает новый ViewModelStore или возвращает существующий ViewModelStore.

Тогда почему ViewModel не выживет из-за недостатка памяти или finish() Scenar ios?

ViewModelStore имеет метод clear():

/**
  *  Clears internal storage and notifies ViewModels that they are no longer used.
  */
public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.onCleared();
    }
    mMap.clear();
}

Таким образом, этот метод clear() вызывается в onDestroy() действия или фрагмента, который очищает HashMap, за исключением изменений конфигурации. Вот код:

if (mViewModelStore != null && !isChangingConfigurations) {
    mViewModelStore.clear();
}

Теперь вы знаете секретный рецепт того, как ViewModel выживает после изменения конфигурации.

Счастливое кодирование ...

ВАЖНО : Я не верю, чтобы брать кредиты на чужую работу. Чтобы сделать его легко доступным в стеке переполнение Я скопировал все из статьи Интересный случай Android ViewModel

...