二、ViewModelStore
ViewModelStore是用来存储 各种ViewModel的,内部是一个HashMap 来保存数据
public class ViewModelStore {
//存放 ViewModel
private final HashMap<String, ViewModel> mMap = new HashMap<>();
//保存ViewModel 如果已经存在,则 触发一次清空逻辑
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
//通过key 获取 ViewModel
final ViewModel get(String key) {
return mMap.get(key);
}
//获取所有存储的key
Set keys() {
return new HashSet<>(mMap.keySet());
}
//清除所有ViewModel 并触发 clear 操作
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ViewModelStore 的获取方式是怎的呢 ?
三、 ViewModelStoreOwner
public interface ViewModelStoreOwner {
/**
- Returns owned {@link ViewModelStore}
- @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
ViewModelStoreOwner 是ViewModelStore 的持有者,是个接口类,那就是谁实现了这个接口,谁就是提供ViewModelStore的生产者。
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory {
private ViewModelStore mViewModelStore;
private ViewModelProvider.Factory mDefaultFactory;
//实现 ViewModelStoreOwner 接口,可以获取 ViewModelStore
@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;
}
//实现 HasDefaultViewModelProviderFactory 接口,对外提供 ViewModelProvider.Factory 生成ViewModel
@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;
}
}
ComponentActivity 实现了 ViewStoreOwner 和 HasDefaultViewModelProviderFactory 接口 用来返回 ViewModelStore 和 ViewModelProvider.Factory
我们看到 都判断了 getApplication() 为null 的情况下会抛出异常,getApplication 返回的 mApplication 是在 Activity 的 attach中赋值的 ,也就是在 attach 之前会一直为空,这之前使用会抛出异常。
Activity.Java
@UnsupportedAppUsage
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) {
/省略其他代码*/
mApplication = application;
/省略其他代码/
}
四、ViewModelProvider.Factory
我们看到 ViewModelProvider中定义了接口 Factory,实现该接口可以返回一个 Factory.
public interface Factory {
@NonNull
T create(@NonNull Class modelClass);
}
ComponentActivity 默认返回的是 SavedStateViewModelFactory,该类实现了 Factory,并禁用了一个参数的 create 接口,实现了两个参数的接口,需要带一个key:
@NonNull
public abstract T create(@NonNull String key,
@NonNull Class modelClass);
@NonNull
@Override
public T create(@NonNull Class modelClass) {
throw new UnsupportedOperationException("create(String, Class<?>) must be called on "
- “implementaions of KeyedFactory”);
}
五、ViewModelProvider
ViewModelProvider 有两个成员变量: ViewModel 工厂类,和ViewModel 存储的地方
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
ViewModelProvider 有三个构造方法:
//传入 ViewModelStoreOwner owner 实现接口返回 ViewModelStore 和 Factoty,如果不是 HasDefaultViewModelProviderFactory,则 NewInstanceFactory 生成一个(采用单例)
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
//传入 ViewModelStoreOwner owner 实现接口返回 ViewModelStore ,Factory 自定义传入
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
//传入 ViewModelStoreOwner ViewModelStore 和 Factory 自定义传入
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
ViewModelProvider 获取ViewModel有两种方法:
//不传入key,默认key 是 androidx.lifecycle.ViewModelProvider.DefaultKey + modelClass.getCanonicalName()
@NonNull
@MainThread
public T get(@NonNull Class 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);
}
//传入key,如果有已经存在 则返回已经存在的否则生成一个 放入 ViewModelStore 中
@SuppressWarnings(“unchecked”)
@NonNull
@MainThread
public T get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
//这里判断了 ViewModel 是都已经存在
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.
}
}
//新生成ViewModel 并放入 ViewModelStore中
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
可以看到 viewModel 是通过 ViewModelStore 按key和 value 存储的,那么就为数据可恢复提供了机制。
六、数据恢复
我们先看下要恢复数据,就要看如何恢复 ViewModelStore
@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;
}
可以看到 获取ViewModelStore会先从 NonConfigurationInstances 获取
接下来我们看下 NonConfigurationInstances 这个是从哪里得来的?,可以看到 mLastNonConfigurationInstances 是在activity attach 时参数传入和赋值的
@UnsupportedAppUsage
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;
/省略部分代码/
}
attach 调用是在 ActivityThread.java 中调用 performLanchActivity 中中调用的。
那么 lastNonConfigurationInstances 是什么时候保存的呢?
ComponentActivity.java
@Override
@Nullable
@SuppressWarnings(“deprecation”)
最后
希望本文对你有所启发,有任何面试上的建议也欢迎留言分享给大家。
好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
好了~如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
[外链图片转存中…(img-uJnHzCEj-1715484142916)]
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!