前言
通过懒加载创建model
kotlin
private val model by lazy {
ViewModelProvider(this)[BaseViewModel::class.java]
}
class BaseViewModel : ViewModel() {
}
ViewmodelProvider实现:
kotlin
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
// 创建Factory
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance
用this的viewModelStore,创建Factory. this是传给ViewModelProvider的一个ViewModelStoreOwner接口的实现。
kotlin
interface ViewModelStoreOwner {
/**
* The owned [ViewModelStore]
*/
val viewModelStore: ViewModelStore
}
ComponentActivity/Fragment实现了ViewModelStoreOwner和HasDefaultViewModelProviderFactory。 ComponentActivity实现:
java
@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.");
}
ensureViewModelStore();
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
getLastNonConfigurationInstance没有就会new一个返回。 Fragment()实现:
implementation 'androidx.fragment:fragment-ktx:1.6.2'
java
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
+ "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
+ "supported");
}
return mFragmentManager.getViewModelStore(this);
}
void performAttach() {
//省略部分代码
mChildFragmentManager.attachController(mHost, createFragmentContainer(), this);
}
FragmentManager:
java
@NonNull
private FragmentManagerViewModel mNonConfig;
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
void attachController(@NonNull FragmentHostCallback<?> host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
//省略部分代码
if (parent != null) {
// fragment如果嵌套了,则去找getChildNonConfig
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
// 获取host的ViewModelStore,自己创建一个ViewModelProvider缓存FragmentManagerViewModel类进去
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
// 自己huost找不到,自己创建一个FragmentManagerViewModel,传入flase,表示不自动缓存
mNonConfig = new FragmentManagerViewModel(false);
}
}
mNonConfig.setIsStateSaved(isStateSaved());
// 设置setNonConfig()
mFragmentStore.setNonConfig(mNonConfig);
FragmentManagerViewModel:
java
private final HashMap<String, ViewModelStore> mViewModelStores = new HashMap<>();
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore == null) {
viewModelStore = new ViewModelStore();
mViewModelStores.put(f.mWho, viewModelStore);
}
return viewModelStore;
}
@NonNull
static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
FACTORY);
return viewModelProvider.get(FragmentManagerViewModel.class);
}
FragmentController
java
public void attachHost(@Nullable Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}
FragmentActivity:
java
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
//内部类
class HostCallbacks extends FragmentHostCallback<FragmentActivity>{
// 省略部分代码
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return FragmentActivity.this.getViewModelStore();
}
}
Fragment的ViewModel其实是委托给了FragmentManager。 Fragment李德mNonConfig.getViewModelStore(f),最后调用host.getViewModelStore()。host是FragmentActivity一个内部类。调用到FragmentActivity.this.getViewModelStore()。FragmentActivity继承了ComponentActivity。Fragment调用的是ComponentActivity的getViewModelStore()构建ViewModelProvider返回。如果不行,自己创建一个FragmentManagerViewModel(fasle)用于处理。 ViewModelStore:
kotlin
open class ViewModelStore {
private val map = mutableMapOf<String, ViewModel>()
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun put(key: String, viewModel: ViewModel) {
val oldViewModel = map.put(key, viewModel)
oldViewModel?.onCleared()
}
/**
* Returns the `ViewModel` mapped to the given `key` or null if none exists.
*/
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
operator fun get(key: String): ViewModel? {
return map[key]
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun keys(): Set<String> {
return HashSet(map.keys)
}
/**
* Clears internal storage and notifies `ViewModel`s that they are no longer used.
*/
fun clear() {
for (vm in map.values) {
vm.clear()
}
map.clear()
}
}
ViewModelStore是一个map,能存ViewModel和清除。 ViewModelProvider:
kotlin
@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
val canonicalName = modelClass.canonicalName
?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
val viewModel = store[key]
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel!!)
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if (viewModel != null) {
// TODO: log a warning.
}
}
val extras = MutableCreationExtras(defaultCreationExtras)
extras[VIEW_MODEL_KEY] = key
return try {
factory.create(modelClass, extras)
} catch (e: AbstractMethodError) {
factory.create(modelClass)
}.also { store.put(key, it) }
}
拿传入的类名canonicalName前拼接DEAFULT_KEY,如果当前store有,且是当前类的实例,强转返回。没有就factory创建。最后调用also缓存进去。 ComonentActivity:
java
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
Fragment:
java
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mDefaultFactory == null) {
Application application = null;
Context appContext = requireContext().getApplicationContext();
while (appContext instanceof ContextWrapper) {
if (appContext instanceof Application) {
application = (Application) appContext;
break;
}
appContext = ((ContextWrapper) appContext).getBaseContext();
}
if (application == null && FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(FragmentManager.TAG, "Could not find Application instance from "
+ "Context " + requireContext().getApplicationContext() + ", you will "
+ "need CreationExtras to use AndroidViewModel with the default "
+ "ViewModelProvider.Factory");
}
mDefaultFactory = new SavedStateViewModelFactory(
application,
this,
getArguments());
}
return mDefaultFactory;
}
上面都返回了SavedStateViewModelFactory。
java
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
// ViewModelProvider calls correct create that support same modelClass with different keys
// If a developer manually calls this method, there is no "key" in picture, so factory
// simply uses classname internally as as key.
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return create(canonicalName, modelClass);
}
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
//判断是否是isAndroidViewModel
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel) {
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
// doesn't need SavedStateHandle
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());
}
}
判断是否是AndroidViewModel,newInstance(),反射。get()是从缓存拿,没有则反射一个新对象,also缓存进去。 Fragment正常情况下用FragmentActivity的ViewModelStore。FragmentActivity的父类ComponentActivity
java
public ComponentActivity() {
//省略部分代码
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
// activity 销毁了
if (event == Lifecycle.Event.ON_DESTROY) {
mContextAwareHelper.clearAvailableContext();
// 判断是否是屏幕旋转等情况下发生了
if (!isChangingConfigurations()) {
// 配置没发生变化,则正常清理
getViewModelStore().clear();
}
}
}
});
}
在ON_DESTROY时候,判断!isChangingConfigurations(),配置没变化,就真正销毁,调用了getViewModelStore().clear();ViewModel不建议持有Context,因为onDestory后才执行清理ViewModel,所以旋转屏幕ViewModel不会丢数据,虽然走了onDestory内部判断了是否旋转屏幕的判断。
Fragment管理ViewModel
Fragment通过this拿ViewModel,两种情况。一种拿FragmentActivity的ViewModelStore。一种自己构建了FragmentManangerViewModel();这个mNonConfig塞进了mFragmentStore。
java
if (parent != null) {
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
// Ensure that the state is in sync with FragmentManager
mNonConfig.setIsStateSaved(isStateSaved());
mFragmentStore.setNonConfig(mNonConfig);
FragmentManager中:
java
private final FragmentStore mFragmentStore = new FragmentStore();
FragmentManagerViewModel getNonConfig() {
return mNonConfig;
}
FragmentManager:
java
private void clearBackStackStateViewModels() {
boolean shouldClear;
if (mHost instanceof ViewModelStoreOwner) {
shouldClear = mFragmentStore.getNonConfig().isCleared();
} else if (mHost.getContext() instanceof Activity) {
Activity activity = (Activity) mHost.getContext();
shouldClear = !activity.isChangingConfigurations();
} else {
shouldClear = true;
}
if (shouldClear) {
for (BackStackState backStackState : mBackStackStates.values()) {
for (String who : backStackState.mFragments) {
mFragmentStore.getNonConfig().clearNonConfigState(who, false);
}
}
}
}
void dispatchDestroy() {
mDestroyed = true;
execPendingActions(true);
endAnimatingAwayFragments();
clearBackStackStateViewModels();
//省略代码
}
判断哪些Fragment需要清理。 FragmentController:
java
public void dispatchDestroyView() {
mHost.mFragmentManager.dispatchDestroyView();
}
FragmentActivity:
java
@Override
protected void onDestroy() {
super.onDestroy();
mFragments.dispatchDestroy();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
FragmentActivity在onDestory调用FragmentController的mFragment.dispatchDestory()->FragmentManager.dispatchDestory->clearBackStackStateViewModels()。FragmentActivity销毁才销毁ViewModel。 FragmentStateManager重新构建时,也会销毁清理对应的ViewModel。
总结
ViewModel保存数据,页面变化能缓存。自动管理,页面销毁自动清理。Fragment和Activity可共用。Fragment可以拿到Activity的ViewModel(只看传入的类名,this)。 ComponentActivity监听onDestroy,清理。Fragment在FragmentActivity的onDestroy会清理。ViewModel就是一个map。通过内部factory反射实现。判断配置发生变化,如:旋转屏幕,等到真正销毁才清空。