文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android ViewModel创建不受横竖屏切换影响怎么实现

2023-07-05 10:13

关注

这篇“Android ViewModel创建不受横竖屏切换影响怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android ViewModel创建不受横竖屏切换影响怎么实现”文章吧。

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 反射创建 ViewModelpublic 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@MainThreadpublic <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@MainThreadpublic <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 个参数:

参数 1 ViewModelStoreOwner:

它对应于 Activity / Fragment 等持有 ViewModel 的宿主,它们内部通过 ViewModelStore 维持一个 ViewModel 的映射表,ViewModelStore 是实现 ViewModel 作用域和数据恢复的关键;

参数 2 Factory:

它对应于 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 是相关联的。

ViewModel 为什么不受 Activity 横竖屏生命周期的影响

1、在 Activity 走到 onDestroy 方法时,做了判断 isChangingConfigurations

Android ViewModel创建不受横竖屏切换影响怎么实现

可以看到,在 ComponentActivity 构造方法中添加了生命周期的判断,当 Activity onDestroy 时,如果是发生了横竖屏切换,就不会走 getViewModelStore().clear(),清理操作,保证了ViewModel 持有的数据还能存在。

2、在 Activity 获取 getViewModelStore 时,

Android ViewModel创建不受横竖屏切换影响怎么实现

Android ViewModel创建不受横竖屏切换影响怎么实现

通过getLastNonConfigurationInstance() 获取 NonConfigurationInstances 实例,从而得到这个实例中的 viewModelStore

Android ViewModel创建不受横竖屏切换影响怎么实现而且,Activity 生命周期的变化都会走这个方法,来保证viewModelStore 不为空。

Android ViewModel创建不受横竖屏切换影响怎么实现

3、onRetainNonConfigurationInstance 调用

在 Activity 屏幕旋转时,onRetainNonConfigurationInstance()onStoponDestroy之间调用

onRetainNonConfigurationInstance() 是个重要的方法

Android ViewModel创建不受横竖屏切换影响怎么实现

这保证了 在销毁前,viewModelStore 实例被拿到并交给 NonConfigurationInstances 实例,将 viewModelStore 赋值给他

Android ViewModel创建不受横竖屏切换影响怎么实现

以上就是关于“Android ViewModel创建不受横竖屏切换影响怎么实现”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯