面试素质三联?
-
ViewModel
优点是啥? 答:保存数据 自动管理。 -
Fragment
能拿Activity的ViewModel么? 答:能吧?。 = = ! -
ViewModel
怎么管理的? 答:母鸡。 -
ViewModel
怎么创建的? 答:母鸡啊结果
回去等消息吧,面试官顺手评价 一个深度不够,基础不牢。
逐步拆解
kotlin
private val model by lazy {
ViewModelProvider(this).get(BaseViewModel::class.java);
}
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
接口
scss
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
看下ViewModelStoreOwner
就一个方法,返回一个ViewModelStore
kotlin
interface ViewModelStoreOwner {
val viewModelStore: ViewModelStore
}
我们常用的ComponentActivity/Fragment
都实现了ViewModelStoreOwner
和HasDefaultViewModelProviderFactory
,我们看下他们的实现getViewModelStore()
的区别。
ComponentActivity的实现方式
scss
@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;
}
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
简略看下核心代码,getLastNonConfigurationInstance
没有,就直接new一个返回。
ComponentActivity
还是比较简单的,相当于自己管自己。
*
Fragment的实现(版本 1.6.2)
less
@NonNull
@Override
public ViewModelStore getViewModelStore() {
// 省略部分代码
return mFragmentManager.getViewModelStore(this);
}
Fragment
调用FragmentManager
的getViewModelStore()
,(下面简称Fm)并把自己传入进去了。
追一下看看 进入 Fm。
less
private FragmentManagerViewModel mNonConfig;
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
FragmentManagerViewModel
ini
FragmentManagerViewModel extends ViewModel{
//省略部分代码
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;
}
//省略部分代码
}
FragmentManager
调用自己的mNonConfig
,传入了Fragment
,mNonConfig
自己就是一个FragmentManagerViewModel
。也是一个ViewModel
。
到这里我们理解Frament 其实委托给了FragmentManager
。
先看下Fm
里的mNonConfig
咋来的。看初始化
FragmentManager
less
void attachController(@NonNull FragmentHostCallback<?> host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
//省略部分代码
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);
}
}
mNonConfig.setIsStateSaved(isStateSaved());
// 设置setNonConfig()
mFragmentStore.setNonConfig(mNonConfig);
FragmentManagerViewModel
csharp
@NonNull
static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
FACTORY);
return viewModelProvider.get(FragmentManagerViewModel.class);
}
我们解析三个创建
if
可以理解为fragment
嵌套 ,去找getChildNonConfig()
。else if
取到host
的viewModelStore
,自己创建了一个ViewModelProvider
缓存FragmentManagerViewModel
类进去。else
自己 host 取不到,自己创建一个FragmentManagerViewModel
,传入false
,表示不自动缓存。
我们看下看下host的真面目
Fragment
csharp
void performAttach() {
//省略部分代码
mChildFragmentManager.attachController(mHost, createFragmentContainer(), this);
}
这host
看下哪里初始化的
FragmentController
less
public void attachHost(@Nullable Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
再看下 这个mHost
怎么初始化的
typescript
public static FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
追一下 进入到了FragmentActivity
scala
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
//内部类
class HostCallbacks extends FragmentHostCallback<FragmentActivity>{
// 省略部分代码
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return FragmentActivity.this.getViewModelStore();
}
}
捋一下,Fragment里面的 mNonConfig.getViewModelStore(f)
, 最后会调用到 host .getViewModelStore()
。而 host 是 FragmentActivity 里的一个内部类。 最后 调用到 FragmentActivity.this.getViewModelStore()
。 而FragmentActivity
继承了ComponentActivity
。
正常情况下来说,FragmentManager
调用的是 ComponentActivity
的getViewModelStore()
,拿到了 然后 构建了一个ViewModelProvider()
返回。
实在不行了,自己 创建一个 FragmentManagerViewModel(false)
用于处理。
ViewModelStore是个啥?
kotlin
open class ViewModelStore {
private val map = mutableMapOf<String, ViewModel>()
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun put(key: String, viewModel: ViewModel) {
val oldViewModel = map.put(key, viewModel)
oldViewModel?.onCleared()
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
operator fun get(key: String): ViewModel? {
return map[key]
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun keys(): Set<String> {
return HashSet(map.keys)
}
fun clear() {
for (vm in map.values) {
vm.clear()
}
map.clear()
}
}
一眼明白,一个map
,能存ViewModel
。 能清除,无了。
ViewModelProvider. get() 又搞了啥?
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
前面拼接 "DEFAULT_KEY"
,如果当前store
有,且是 是当前类的实例,就强转返回。 没有就factory
创建。最后调用 also
缓存进去。看下 factory
。
前面我们知道ComponentActivity
和Fragment
实现了HasDefaultViewModelProviderFactory
。
- ComponentActivity
less
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
-
Fragment
ini@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()
。看下SavedStateViewModelFactory
的creat()
;
- SavedStateViewModelFactory.create()
less
@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 缓存进去。
至此,还没成艺术。
ViewModel 的自我修养(管理)?
认真阅读的朋友们都知道,Fragment
正常情况下用FragmentActivity
的ViewModelStore
。
- 看下
FragmentActivity
的 父类ComponentActivity
构造参数。
less
public ComponentActivity() {
//省略部分代码
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
mContextAwareHelper.clearAvailableContext();
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
我们看到 做了个监听,在 *ON_DESTROY*
的时候, 判断了下!isChangingConfigurations()
也就是 不是发生了配置变化,是真正销毁的时候,调用了 getViewModelStore().clear()
;
其实就是相当于把当前缓存的ViewModel
的对象嘎嘎的清空了。
经常说ViewModel
为什么不建议持有Context
。 因为是在onDestroy
后才执行。
也为什么说旋转屏幕ViewModel
不会丢数据。因为虽然走了onDestroy
但是内部判断了是否旋转屏幕。
-
那
Fragment
怎么管理的呢我们记得
Fragment
在 this 那一步的时候,有2种 情况,一种 拿FragmentActivity
的ViewModelStore 。一种自己构建了一个FragmentManagerViewModel()
;这个
mNonConfig
其实在创建后 赛进了mFragmentStore
。iniif (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);
mFragmentStore.setNonConfig(mNonConfig);
把mNonConfig
传出去了,追着看一下。进入
FragmentStore
。发现
FragmentStore
是在FragmentManager
初始化就创建了javaprivate final FragmentStore mFragmentStore = new FragmentStore();
FragmentStore
里调用mNonConfig
查看下被调用的地方。csharpFragmentManagerViewModel getNonConfig() { return mNonConfig; }
进入
FragmentManager.java
->
clearBackStackStateViewModels()
这里去判断了哪些Fragment 需要清理
iniprivate 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); } } } }
->
dispatchDestroy()
scssvoid dispatchDestroy() { mDestroyed = true; execPendingActions(true); endAnimatingAwayFragments(); clearBackStackStateViewModels(); //省略代码 }
->
FragmentController.java
->dispatchDestroy()
csharppublic void dispatchDestroyView() { mHost.mFragmentManager.dispatchDestroyView(); }
->
FragmentActivity.java
->onDestroy(){}
scss@Override protected void onDestroy() { super.onDestroy(); mFragments.dispatchDestroy(); mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY); }
把整个调用反过来看一下,
FragmentActivity
在onDestroy
调用mFragments.dispatchDestroy()
; (FragmentController.java
)->
FragmentManager.dispatchDestroy()
(FragmentManger.java
)->
clearBackStackStateViewModels()
。可以理解为
FragmentActivity
销毁才销毁。另外
FragmentStateManager
里 重新构建的时候,也会销毁清理对应的ViewModel
。感兴趣可以看一下。scssvoid moveToExpectedState{ //省列部分代码 case Fragment.ATTACHED: if (mFragment.mBeingSaved && mFragmentStore.getSavedState(mFragment.mWho) == null) { mFragmentStore.setSavedState(mFragment.mWho, saveState()); } destroy(); } void destroy() { //省列部分代码 if (shouldDestroy) { mFragment.performDestroy(); if ((beingRemoved && !mFragment.mBeingSaved) || shouldClear) { mFragmentStore.getNonConfig().clearNonConfigState(mFragment, false); } mFragment.performDestroy(); } }
面试的侃侃而谈
-
优势
- 保存数据,页面变化能缓存
- 自动管理,页面销毁自动清理
Fragment
和Activity
可共用。
-
Fragment
能拿Activity
的ViewModel
么?- 能 ,毕竟那玩意只看传入的类名,把Activity 一传就行。
-
怎么自动管理的?
- ComponentActivity 监听onDestroy ,清理
- Fragment 在FragmentActivity 的 onDestroy 会清理。
-
ViewModelStore 知道么?
- 知道 ,一个map 就是干。
-
知道怎么创建的么?
- 内部 factory 反射就是干。
-
为啥旋转还能保存数据?
判断了是配置变化,如旋转屏幕等,等到真正销毁才清空。
-
剩下的自行发挥