ViewModel

Posted by ooftf on April 24, 2021

项目配置ViewModel支持

1
2
    def lifecycle_version = "2.3.1"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

如果要使用 ViewModelScope 需要添加

1
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'

为什么横竖屏切换后,Activity是新对象,ViewModel还是原来的对象

  • 由代码可知我们获取ViewModel 是通过 ViewModelProvider.get 方法获取的
    1
    
    ViewModelProvider(this).get(MyViewModel::class.java)
    
  • 查看内部实现可知 ViewModel 是通过 mViewModelStore.get(key) 方法获取的,此处Key为固定值 “androidx.lifecycle.ViewModelProvider.DefaultKey”
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
      @NonNull
      @MainThread
      public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
          ViewModel viewModel = mViewModelStore.get(key);
    
          if (modelClass.isInstance(viewModel)) {
              if (mFactory instanceof OnRequeryFactory) {
                  ((OnRequeryFactory) mFactory).onRequery(viewModel);
              }
              return (T) viewModel;
          } else {
              //noinspection StatementWithEmptyBody
              if (viewModel != null) {
                  // TODO: log a warning.
              }
          }
          if (mFactory instanceof KeyedFactory) {
              viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
          } else {
              viewModel = mFactory.create(modelClass);
          }
          mViewModelStore.put(key, viewModel);
          return (T) viewModel;
      }
    
  • 此处的mViewModelStore是我们创建 ViewModelProvider 传入的 ViewModelStoreOwner 通过 ViewModelStoreOwner.getViewModelStore()获取到的
    1
    2
    3
    4
    5
    
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
    
  • ComponentActivity.getViewModelStore() 是在Activity的父类 androidx.activity.ComponentActivity 内实现的
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
      @NonNull
      @Override
      public ViewModelStore getViewModelStore() {
          if (getApplication() == null) {
              throw new IllegalStateException("Your activity is not yet attached to the "
                      + "Application instance. You can't request ViewModel before onCreate call.");
          }
          if (mViewModelStore == null) {
              NonConfigurationInstances nc =
                      (NonConfigurationInstances) getLastNonConfigurationInstance();
              if (nc != null) {
                  // Restore the ViewModelStore from NonConfigurationInstances
                  mViewModelStore = nc.viewModelStore;
              }
              if (mViewModelStore == null) {
                  mViewModelStore = new ViewModelStore();
              }
          }
          return mViewModelStore;
      }
    
  • 通过学习横竖屏切换相关的知识可知:我横竖屏切换时可以通过 onRetainNonConfigurationInstance 方法返回需要保存的对象,然后在新的Activity中通过 getLastNonConfigurationInstance 方法 获取到保存的对象

  • 查看 ComponentActivity.onRetainNonConfigurationInstance 方法可知,在横竖屏切换时保存了viewModelStore对象。因此新旧Activity获取到的viewModelStore是同一个实例,自然获取到的ViewModel也是同一个实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
      @Override
      @Nullable
      public final Object ComponentActivity.onRetainNonConfigurationInstance() {
          Object custom = onRetainCustomNonConfigurationInstance();
    
          ViewModelStore viewModelStore = mViewModelStore;
          if (viewModelStore == null) {
              // No one called getViewModelStore(), so see if there was an existing
              // ViewModelStore from our last NonConfigurationInstance
              NonConfigurationInstances nc =
                      (NonConfigurationInstances) getLastNonConfigurationInstance();
              if (nc != null) {
                  viewModelStore = nc.viewModelStore;
              }
          }
    
          if (viewModelStore == null && custom == null) {
              return null;
          }
    
          NonConfigurationInstances nci = new NonConfigurationInstances();
          nci.custom = custom;
          nci.viewModelStore = viewModelStore;
          return nci;
      }
    

ViweModel.clear 的调用时机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public ComponentActivity() {
    ...
    getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                if (!isChangingConfigurations()) {
                    getViewModelStore().clear();
                }
            }
        }
    });
    ...
}

由代码可知 Activity在创建的时候通过Lifecycle 监听ON_DESTROY生命周期,通过isChangingConfigurations判断如果不是横竖屏切换,就会执行clear方法