这篇“Android ViewModel创建不受横竖屏切换影响怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android ViewModel创建不受横竖屏切换影响怎么实现”文章吧。
在我们项目中, 引入了viewModel 做MVI 设计模式的组成部分,它是JetPack 组件库中的重要成员。今天来了解下它。
// 在 Activity 中使用
class MainActivity : AppCompatActivity() {
// 使用 Activity 的作用域
private val viewModel : MainViewModel by viewModels()
}
// 在 Fragment 中使用
class MainFragment : Fragment() {
// 使用 Activity 的作用域,与 MainActivity 使用同一个对象
val activityViewModel : MainViewModel by activityViewModels()
// 使用 Fragment 的作用域
val viewModel : MainViewModel by viewModels()
}
// ViewModel 创建工厂
private final Factory mFactory;
// ViewModel 存储容器
private final ViewModelStore mViewModelStore;
// 默认使用 NewInstanceFactory 反射创建 ViewModel
public ViewModelProvider(ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), ... NewInstanceFactory.getInstance());
}
// 自定义 ViewModel 创建工厂
public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) {
this(owner.getViewModelStore(), factory);
}
// 记录宿主的 ViewModelStore 和 ViewModel 工厂
public ViewModelProvider(ViewModelStore store, Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
@NonNull
@MainThread
public <T extends ViewModel> T get(Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
// 使用类名作为缓存的 KEY
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
// Fragment
@NonNull
@MainThread
public <T extends ViewModel> T get(String key, Class<T> modelClass) {
// 1. 先从 ViewModelStore 中取缓存
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
// 2. 使用 ViewModel 工厂创建实例
viewModel = mFactory.create(modelClass);
...
// 3. 存储到 ViewModelStore
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
// 默认的 ViewModel 工厂
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@NonNull
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
// 反射创建 ViewModel 对象
return modelClass.newInstance();
}
}
可以看到:
ViewModel 实例的方法最终是通过 ViewModelProvider 完成的。ViewModelProvider 可以理解为创建 ViewModel 的工具类,它需要 2 个参数:
它对应于 Activity / Fragment 等持有 ViewModel 的宿主,它们内部通过 ViewModelStore 维持一个 ViewModel 的映射表,ViewModelStore 是实现 ViewModel 作用域和数据恢复的关键;
它对应于 ViewModel 的创建工厂,缺省时将使用默认的 NewInstanceFactory 工厂来反射创建 ViewModel 实例。
创建 ViewModelProvider 工具类后,你将通过 get() 方法来创建 ViewModel 的实例。get() 方法内部首先会通过 ViewModel 的全限定类名从映射表(ViewModelStore)中取缓存,未命中才会通过 ViewModel 工厂创建实例再缓存到映射表中。 正因为同一个 ViewModel 宿主使用的是同一个 ViewModelStore 映射表,因此在同一个宿主上重复调用 ViewModelProvider.get() 返回同一个 ViewModel 实例。
// ViewModel 本质上就是一个映射表而已
public class ViewModelStore {
// <String - ViewModel> 哈希表
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();
}
}
ViewModel 宿主是 ViewModelStoreOwner 接口的实现类,例如 ComponentActivity:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware,
LifecycleOwner,
ViewModelStoreOwner ... {
// ViewModel 的存储容器
private ViewModelStore mViewModelStore;
// ViewModel 的创建工厂
private ViewModelProvider.Factory mDefaultFactory;
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (mViewModelStore == null) {
// 已简化过程
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
}
由此,ViewModel 的创建其实跟activity 是相关联的。
可以看到,在 ComponentActivity
构造方法中添加了生命周期的判断,当 Activity onDestroy 时,如果是发生了横竖屏切换,就不会走 getViewModelStore().clear()
,清理操作,保证了ViewModel 持有的数据还能存在。
通过getLastNonConfigurationInstance()
获取 NonConfigurationInstances
实例,从而得到这个实例中的 viewModelStore
而且,Activity 生命周期的变化都会走这个方法,来保证
viewModelStore
不为空。
在 Activity 屏幕旋转时,onRetainNonConfigurationInstance()
在onStop
和onDestroy
之间调用
onRetainNonConfigurationInstance()
是个重要的方法
这保证了 在销毁前,viewModelStore
实例被拿到并交给 NonConfigurationInstances
实例,将 viewModelStore
赋值给他
以上就是关于“Android ViewModel创建不受横竖屏切换影响怎么实现”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://juejin.cn/post/7207689082183696442