ViewModel 是 Architecture Components 官方架构组件之一。
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据,它让数据可在发生屏幕旋转等配置更改后继续留存。
简单示例 实现 ViewModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class MyViewModel : ViewModel () { private val users: MutableLiveData<List<User>> by lazy { MutableLiveData().also { loadUsers() } } fun getUsers () : LiveData<List<User>> { return users } private fun loadUsers () { } }
在 Activity 或 Fragment 中使用 ViewModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MyActivity : AppCompatActivity () { override fun onCreate (savedInstanceState: Bundle ?) { val model: MyViewModel by viewModels() model.getUsers().observe(this , Observer<List<User>>{ users -> }) } }
如果重新创建了该 Activity,它接收的 MyViewModel 实例与第一个 Activity 创建的实例相同。当所有者 Activity 完成时,框架会调用 ViewModel 对象的 onCleared()
方法,以便它清理资源。
ViewModel 绝不能引用视图、 Lifecycle 或可能存储对 Activity 上下文的引用的任何类。
ViewModel 妙用 Fragment 与 Fragment 通信 Fragment 可以使用其 Activity 范围共享 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 26 27 28 29 30 31 32 33 34 35 36 37 class SharedViewModel : ViewModel () { val selected = MutableLiveData<Item>() fun select (item: Item ) { selected.value = item } } class MasterFragment : Fragment () { private lateinit var itemSelector: Selector private val model: SharedViewModel by activityViewModels() override fun onViewCreated (view: View , savedInstanceState: Bundle ?) { super .onViewCreated(view, savedInstanceState) itemSelector.setOnClickListener { item -> } } } class DetailFragment : Fragment () { private val model: SharedViewModel by activityViewModels() override fun onViewCreated (view: View , savedInstanceState: Bundle ?) { super .onViewCreated(view, savedInstanceState) model.selected.observe(viewLifecycleOwner, Observer<Item> { item -> }) } }
Activity 与 Fragment 通信 与 Fragment 和 Fragment 通信同理。
ViewModel 的生命周期 ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 Lifecycle。
对 Activity,是 Activity 完成时清除;对 Fragment,时 Fragment 分离时。
ViewModel 原理 从获取 ViewModel 实例的方法开始:
1 val model: MyViewModel by viewModels()
或
1 MyViewModel model = new ViewModelProvider (this ).get(MyViewModel.class);
Kotlin 版只是对 Java 写法的一个 Lazy Delegate,所以我们从 ViewModelProvider 开始研究即可。
构造 ViewModelProvider 获取 ViewModel 的入口首先构造了一个 ViewModelProvider 的实例,然后调用了其 get 方法,我们先看 ViewModelProvider 的构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ViewModelProvider { private final Factory mFactory; private final ViewModelStore mViewModelStore; public ViewModelProvider (@NonNull ViewModelStoreOwner owner) { this (owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); } public ViewModelProvider (@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) { this (owner.getViewModelStore(), factory); } public ViewModelProvider (@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; mViewModelStore = store; } }
其构造函数就是初始化了两个成员 mFactory
和 mViewModelStore
,它们分别是 ViewModelStoreOwner
和 ViewModelProvider.Factory
的实例。
调用构造函数时,我们传入的 AppCompatActivity 或 Fragment 都实现了 ViewModelStoreOwner
和 HasDefaultViewModelProviderFactory
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class AppCompatActivity extends FragmentActivity implements ... {} public class FragmentActivity extends ComponentsActivity implements ... {} public class ComponentActivity extends androidx .core.app.ComponentActivity implements LifecycleOwner , ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner, OnBackPressedDispatcherOwner { } public class Fragment implements ComponentCallbacks , OnCreateContextMenuListener, LifecycleOwner, ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner { }
之后再调用 ViewModelProvider 的 get()
方法获取 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 26 27 28 29 30 public <T extends ViewModel > T get (@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null ) { throw new IllegalArgumentException ("Local and anonymous classes can not be ViewModels" ); } return get(DEFAULT_KEY + ":" + canonicalName, modelClass); } 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 { if (viewModel != null ) { } } if (mFactory instanceof KeyedFactory) { viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass); } else { viewModel = (mFactory).create(modelClass); } mViewModelStore.put(key, viewModel); return (T) viewModel; }
逻辑非常简单:
从 mViewModelStore 根据 key 获取 ViewModel 缓存;
如果 viewModel 是 modelClass 的实例,mFactory 是 OnRequeryFactory 的实例,就调用 mFactory.onRequery 重新获取 viewModel;
如果 mFactory 是 KeyedFactory 的实例,调用其 create 方法用 key 和 class 构建 ViewModel
否则直接调用 create
通过 class 构建 ViewModel
把 viewModel 放进 mViewModelStore 缓存并返回 viewModel。
ViewModelStore 和 ViewModelProvider.Factory ViewModelProvider 的三个构造函数最终都是初始化其 mFactory
和 mViewModelStore
。
下面对这两个成员变量进行分析。
ViewModelStore 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 26 27 28 29 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()); } public final void clear () { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }
ComponentActivity 和 Fragment 都实现了 ViewModelStoreOwner
,它是一个接口,实现它返回一个 ViewModelStore
。
1 2 3 4 public interface ViewModelStoreOwner { @NonNull ViewModelStore getViewModelStore () ; }
FragmentActivity 覆盖了 ComponentActivity 中的实现:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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 ) { mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null ) { mViewModelStore = new ViewModelStore (); } } return mViewModelStore; } static final class NonConfigurationInstances { Object custom; ViewModelStore viewModelStore; FragmentManagerNonConfig fragments; } @Override public final Object onRetainNonConfigurationInstance () { Object custom = onRetainCustomNonConfigurationInstance(); FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); if (fragments == null && mViewModelStore == null && custom == null ) { return null ; } NonConfigurationInstances nci = new NonConfigurationInstances (); nci.custom = custom; nci.viewModelStore = mViewModelStore; nci.fragments = fragments; return nci; } @Override protected void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null && nc.viewModelStore != null && mViewModelStore == null ) { mViewModelStore = nc.viewModelStore; } }
根据 Activity 类中 onRetainNonConfigurationInstance()
的注释我们知道,该方法在配置改变时我们重建 Activity 中 destroy 原 Activity 的时候会被系统调用。而在 onCreate
方法中我们会通过 getLastNonConfigurationInstance()
获取到之前 onRetainNonConfigurationInstance()
保存的对象,由于 mViewModelStore 会被保存在 NonConfigurationInstances 中,所以旋转屏幕等配置改变的情况我们依然会获得相同的 ViewModelStore。
这个过程是由 ActivityThread 中的 performDestroyActivity
方法完成的,它会调用 Activity 的 retainNonConfigurationInstances
方法,而该方法会调用 Activity 子类的 onRetainNonConfigurationInstance()
方法作为自己的 NonConfigurationInstances.activity
保存下来。
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 static final class NonConfigurationInstances { Object activity; HashMap<String, Object> children; FragmentManagerNonConfig fragments; ArrayMap<String, LoaderManager> loaders; VoiceInteractor voiceInteractor; } @Nullable public Object getLastNonConfigurationInstance () { return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null ; } NonConfigurationInstances retainNonConfigurationInstances () { Object activity = onRetainNonConfigurationInstance(); HashMap<String, Object> children = onRetainNonConfigurationChildInstances(); FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); mFragments.doLoaderStart(); mFragments.doLoaderStop(true ); ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig(); if (activity == null && children == null && fragments == null && loaders == null && mVoiceInteractor == null ) { return null ; } NonConfigurationInstances nci = new NonConfigurationInstances (); nci.activity = activity; nci.children = children; nci.fragments = fragments; nci.loaders = loaders; if (mVoiceInteractor != null ) { mVoiceInteractor.retainInstance(); nci.voiceInteractor = mVoiceInteractor; } return nci; }
重建 Activity 的时候,ActivityThread 在 performLaunchActivity
中会调用 Activity 的 attach()
方法对 mLastNonConfigurationInstances 赋值。
1 2 3 4 5 6 7 8 9 10 11 final void attach (Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) { mLastNonConfigurationInstances = lastNonConfigurationInstances; }
ViewModelProvider.Factory ViewModelProvider.Factory 是工厂模式的实现:
1 2 3 4 public interface Factory { @NonNull <T extends ViewModel > T create (@NonNull Class<T> modelClass) ; }
HasDefaultViewModelProviderFactory 是一个接口,它主要用于标记 ViewModelStoreOwner 有一个可以提供 ViewModelFactory 的方法:
1 2 3 4 public interface HasDefaultViewModelProviderFactory { @NonNull ViewModelProvider.Factory getDefaultViewModelProviderFactory () ; }
该方法在 ComponentActivity 中的实现如下,构造了一个 SavedStateViewModelFactory。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @NonNull @Override public ViewModelProvider.Factory getDefaultViewModelProviderFactory () { 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 (mDefaultFactory == null ) { mDefaultFactory = new SavedStateViewModelFactory ( getApplication(), this , getIntent() != null ? getIntent().getExtras() : null ); } return mDefaultFactory; }
而 SavedStateViewModelFactory 继承自 ViewModelProvider.KeyedFactory
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public final class SavedStateViewModelFactory extends ViewModelProvider .KeyedFactory { private final Application mApplication; private final ViewModelProvider.AndroidViewModelFactory mFactory; private final Bundle mDefaultArgs; private final Lifecycle mLifecycle; private final SavedStateRegistry mSavedStateRegistry; public SavedStateViewModelFactory (@NonNull Application application, @NonNull SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs) { mSavedStateRegistry = owner.getSavedStateRegistry(); mLifecycle = owner.getLifecycle(); mDefaultArgs = defaultArgs; mApplication = application; mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } @NonNull @Override public <T extends ViewModel > T create (@NonNull String key, @NonNull Class<T> modelClass) { boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass); Constructor<T> constructor; if (isAndroidViewModel) { constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE); } else { constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE); } if (constructor == null ) { return mFactory.create(modelClass); } SavedStateHandleController controller = SavedStateHandleController.create( mSavedStateRegistry, mLifecycle, key, mDefaultArgs); try { T viewmodel; if (isAndroidViewModel) { viewmodel = constructor.newInstance(mApplication, controller.getHandle()); } else { viewmodel = constructor.newInstance(controller.getHandle()); } viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller); return viewmodel; } catch (IllegalAccessException e) { throw new RuntimeException ("Failed to access " + modelClass, e); } catch (InstantiationException e) { throw new RuntimeException ("A " + modelClass + " cannot be instantiated." , e); } catch (InvocationTargetException e) { throw new RuntimeException ("An exception happened in constructor of " + modelClass, e.getCause()); } } @NonNull @Override public <T extends ViewModel > T create (@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null ) { throw new IllegalArgumentException ("Local and anonymous classes can not be ViewModels" ); } return create(canonicalName, modelClass); } }
通过前面的分析我们知道 ViewModelProvider 的 mFactory 是 KeyedFactory 的实例时,会调用其两个参数的 create()
方法创建 ViewModel。该方法通过传入的 class 检查是 AndroidViewModel 还是普通 ViewModel 的实例,然后构造对应的实例。
SavedStateViewModelFactory 的作用主要是用于创建可以保存当前页面的数据的 ViewModel。也就是说当我们的页面数据还是保存在页面的时候,我们可以通过该默认工厂,把页面的数据存储到由 SavedStateViewModelFactory 所创建的 ViewModel 中进行保存。
前提是:需要我们的 ViewModel 的最终实现类的构造方法签名和下面的 ANDROID_VIEWMODEL_SIGNATURE
或 VIEWMODEL_SIGNATURE
一样才会起到上面说的效果:
1 2 3 4 5 6 7 class SaveStateViewModel (val savedStateHandle: SavedStateHandle) : ViewModel() {} private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class []{Application.class, SavedStateHandle.class}; private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class []{SavedStateHandle.class};
否则,就会调用 ViewModelProvider.AndroidViewModelFactory 中的 create()
方法去创建 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public static class AndroidViewModelFactory extends ViewModelProvider .NewInstanceFactory { private static AndroidViewModelFactory sInstance; @NonNull public static AndroidViewModelFactory getInstance (@NonNull Application application) { if (sInstance == null ) { sInstance = new AndroidViewModelFactory (application); } return sInstance; } private Application mApplication; public AndroidViewModelFactory (@NonNull Application application) { mApplication = application; } @NonNull @Override public <T extends ViewModel > T create (@NonNull Class<T> modelClass) { if (AndroidViewModel.class.isAssignableFrom(modelClass)) { try { return modelClass.getConstructor(Application.class).newInstance(mApplication); } catch (NoSuchMethodException e) { throw new RuntimeException ("Cannot create an instance of " + modelClass, e); } catch (IllegalAccessException e) { throw new RuntimeException ("Cannot create an instance of " + modelClass, e); } catch (InstantiationException e) { throw new RuntimeException ("Cannot create an instance of " + modelClass, e); } catch (InvocationTargetException e) { throw new RuntimeException ("Cannot create an instance of " + modelClass, e); } } return super .create(modelClass); } }
ViewModel.onCleared() ViewModel 同时提供了一个清理资源的方法 onCleared()
,那么它是什么时候被调用的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class ViewModel { protected void onCleared () { } @MainThread final void clear () { mCleared = true ; if (mBagOfTags != null ) { synchronized (mBagOfTags) { for (Object value : mBagOfTags.values()) { closeWithRuntimeException(value); } } } onCleared(); } }
很明显它在 clear()
方法中被调用。
而 ViewModel 的 clear()
则是被 ViewModelStore 的 clear()
调用:
1 2 3 4 5 6 7 8 9 10 11 public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap <>(); public final void clear () { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }
追踪该方法发现它在 ComponentActivity 的默认构造中被调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public ComponentActivity () { Lifecycle lifecycle = getLifecycle(); if (lifecycle == null ) { throw new IllegalStateException ("getLifecycle() returned null in ComponentActivity's " + "constructor. Please make sure you are lazily constructing your Lifecycle " + "in the first call to getLifecycle() rather than relying on field " + "initialization." ); } 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(); } } } }); }
非常明显就是对生命周期进行了监听,在 Lifecycle.Event.ON_DESTROY
被触发的时候调用,清理资源。
ViewModel 高级使用 AndroidViewModel AndroidViewModel 是 ViewModel 的一个子类,它可以在 ViewModel 中获取 Application。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class AndroidViewModel extends ViewModel { @SuppressLint("StaticFieldLeak") private Application mApplication; public AndroidViewModel (@NonNull Application application) { mApplication = application; } @SuppressWarnings("TypeParameterUnusedInFormals") @NonNull public <T extends Application > T getApplication () { return (T) mApplication; } }
我们使用时只需要继承它然后实现对应的构造函数即可。
保存状态 我们分析源码时发现当 ViewModel 的构造函数满足如下两种情况时:
1 2 3 private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class []{Application.class, SavedStateHandle.class}; private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class []{SavedStateHandle.class};
它会调用对应的构造方法来创建 ViewModel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SavedStateHandleController controller = SavedStateHandleController.create( mSavedStateRegistry, mLifecycle, key, mDefaultArgs); try { T viewmodel; if (isAndroidViewModel) { viewmodel = constructor.newInstance(mApplication, controller.getHandle()); } else { viewmodel = constructor.newInstance(controller.getHandle()); } viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller); return viewmodel; } catch (IllegalAccessException e) { throw new RuntimeException ("Failed to access " + modelClass, e); } catch (InstantiationException e) { throw new RuntimeException ("A " + modelClass + " cannot be instantiated." , e); } catch (InvocationTargetException e) { throw new RuntimeException ("An exception happened in constructor of " + modelClass, e.getCause()); }
ViewModel 构造器加入 SavedStateHandle 参数,并将想要保存的数据使用该 handle 保存。
1 2 3 class SaveStateViewModel (private val savedStateHandle: SavedStateHandle) : ViewModel() { val liveDataText: LiveData<TestModel> = savedStateHandle.getLiveData(LIVE_DATE_KEY) }
总结 ViewModel 是一个非常方便使用的 Jetpack 架构组件,但小小的一个类却包含了非常精细巧妙的设计,非常值得学习。