设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间07 现在时间07 缓存数据 女人不要只算计自己喜欢的任何物品多少钱,要计算自己的青春还剩多少年;要懂得爱自己,舍得爱自己;不为别人,只为那个限量版的自己!

女人不要只算计自己喜欢的任何物品多少钱,要计算自己的青春还剩多少年;要懂得爱自己,舍得爱自己;不为别人,只为那个限量版的自己!

查看: 994|回复: 2

Android ViewModel的作用深入讲解

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:220
  • 打卡月天数:0
  • 打卡总奖励:3305
  • 最近打卡:2025-06-25 18:55:13
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
414
主题
376
精华
0
金钱
4517
积分
837
注册时间
2023-1-5
最后登录
2025-6-25

发表于 2023-7-21 01:11:53 | 显示全部楼层 |阅读模式
ViewModel它的作用是什么呢
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存(官方解释)
看到这里我们就可以总结viewmodel的两个作用点,第一viewmodel在activity和fragment销毁时自己也会被清除掉,第二点viewmodel在屏幕旋转activity销毁后重建可以显示之前数据。
那么问题就来了viewmodel是怎么保存数据的以及自动释放掉内存? 这两个问题弄懂了viewmodel的面纱也就被我们揭开了。
那我们就直接从最简单的使用viewmodel开始说起
  1. class UserViewModel : ViewModel() {
  2.     var age: Int = 0
  3. }
  4. class MainActivity : AppCompatActivity() {
  5.     override fun onCreate(savedInstanceState: Bundle?) {
  6.         super.onCreate(savedInstanceState)
  7.         val userViewModel =
  8.             ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[UserViewModel::class.java]
  9.         val mView = ActivityMainBinding.inflate(layoutInflater)
  10.         setContentView(mView.root)
  11.         mView.tv.text = userViewModel.age.toString()
  12.         var sum = 0
  13.         mView.tv.setOnClickListener {
  14.             sum = sum.inc()
  15.             userViewModel.age = sum
  16.         }
  17.     }
  18. }
复制代码
随着我们不停的点击 sum会越来越大 当我们旋转屏幕的时候 activity会重建  但是我们获取的age却是最后一次点击的值,这就证明了我们数据是被保存了下来。那么viewmodel是怎么做到的呢?我们从源码角度去分析
以下源码分析是从Android13分析的
看源码viewmodel是一个抽象类,并不能看出什么。那么我们就得换一个思路去思考了。既然viewmodel是和activity有关系,而且在activity旋转销毁时还能做到复用,那么我们就从activity中去寻找。
一级一级寻找发现在ComponentActivity实现了一个ViewModelStoreOwner接口 看命名是和viewmodel有点关系看下这个接口内部有什么
  1. public interface ViewModelStoreOwner {
  2.     /**
  3.      * Returns owned {@link ViewModelStore}
  4.      *
  5.      * @return a {@code ViewModelStore}
  6.      */
  7.     @NonNull
  8.     ViewModelStore getViewModelStore();
  9. }
  10. //代码很简洁 一个抽象方法 返回值ViewModelStore 顾名思义这个类的功能也就呼之欲出,存储viewmodel,那我们就看实现类中怎么处理的
  11. //ComponentActivity中实现
  12.   @NonNull
  13.     @Override
  14.     public ViewModelStore getViewModelStore() {
  15.         if (getApplication() == null) {
  16.             throw new IllegalStateException("Your activity is not yet attached to the "
  17.                     + "Application instance. You can't request ViewModel before onCreate call.");
  18.         }
  19.         ensureViewModelStore();
  20.         return mViewModelStore;
  21.     }
  22. //我们直接看ensureViewModelStore()方法
  23. void ensureViewModelStore() {
  24.         if (mViewModelStore == null) {
  25.             NonConfigurationInstances nc =
  26.                     (NonConfigurationInstances) getLastNonConfigurationInstance();
  27.             if (nc != null) {
  28.                 // Restore the ViewModelStore from NonConfigurationInstances
  29.                 mViewModelStore = nc.viewModelStore;
  30.             }
  31.             if (mViewModelStore == null) {
  32.                 mViewModelStore = new ViewModelStore();
  33.             }
  34.         }
  35.     }
  36. //ensureViewModelStore方法看来是为了获取ViewModelStore,那我们在具体看下ViewModelStore内部做了什么?
  37. public class ViewModelStore {
  38.     private final HashMap<String, ViewModel> mMap = new HashMap<>();
  39.     final void put(String key, ViewModel viewModel) {
  40.         ViewModel oldViewModel = mMap.put(key, viewModel);
  41.         if (oldViewModel != null) {
  42.             oldViewModel.onCleared();
  43.         }
  44.     }
  45.     final ViewModel get(String key) {
  46.         return mMap.get(key);
  47.     }
  48.     Set<String> keys() {
  49.         return new HashSet<>(mMap.keySet());
  50.     }
  51.     /**
  52.      *  Clears internal storage and notifies ViewModels that they are no longer used.
  53.      */
  54.     public final void clear() {
  55.         for (ViewModel vm : mMap.values()) {
  56.             vm.clear();
  57.         }
  58.         mMap.clear();
  59.     }
  60. }
  61. //看到这里就明了了,果然和我们猜想的一样,ViewModelStore是用来缓存ViewModel的
复制代码
经过我们分析已经明白了viewmodel是被ViewModelStore缓存起来的,那么又是如何做到在activity不正常销毁时去恢复数据的呢?
在ComponentActivity在发现还有另一个方法中使用了ViewModelStore
onRetainNonConfigurationInstance方法
  1. public final Object onRetainNonConfigurationInstance() {
  2.         // Maintain backward compatibility.
  3.         Object custom = onRetainCustomNonConfigurationInstance();
  4.         ViewModelStore viewModelStore = mViewModelStore;
  5.         if (viewModelStore == null) {
  6.             // No one called getViewModelStore(), so see if there was an existing
  7.             // ViewModelStore from our last NonConfigurationInstance
  8.             NonConfigurationInstances nc =
  9.                     (NonConfigurationInstances) getLastNonConfigurationInstance();
  10.             if (nc != null) {
  11.                 viewModelStore = nc.viewModelStore;
  12.             }
  13.         }
  14.         if (viewModelStore == null && custom == null) {
  15.             return null;
  16.         }
  17.         NonConfigurationInstances nci = new NonConfigurationInstances();
  18.         nci.custom = custom;
  19.         nci.viewModelStore = viewModelStore;
  20.         return nci;
  21.     }
复制代码
方法体内的代码也很容易理解 如果viewModelStore为null 就去给它赋值。那么这个方法是在什么时候执行的呢?经过一番debug发现在activity切换横竖屏的时候 这个方法就被触发了 而getViewModelStore方法在activity创建的时候就执行了。我们现在知道了viewModelStore的创建时机,那么viewmodel是如何存储到viewModelStore中的呢?
还记得我们写的示例代码吗?
  1.   val userViewModel =
  2.             ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
  3.                 .get(UserViewModel::class.java)
复制代码
我们就从ViewModelProvider入手
  1. public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
  2.         owner.viewModelStore,
  3.         factory,
  4.         defaultCreationExtras(owner)
  5.     )
复制代码
第一个入参就是我们activity实例 然后拿到我们自己的viewModelStore,这个时候的viewModelStore已经创建好了,看第二个参数是Factory 我们传递的是NewInstanceFactory这个一看就是单例,内部实现了一个create方法
  1.   public open class NewInstanceFactory : Factory {
  2.         @Suppress("DocumentExceptions")
  3.         override fun <T : ViewModel> create(modelClass: Class<T>): T {
  4.             return try {
  5.                 modelClass.newInstance()
  6.             } catch (e: InstantiationException) {
  7.                 throw RuntimeException("Cannot create an instance of $modelClass", e)
  8.             } catch (e: IllegalAccessException) {
  9.                 throw RuntimeException("Cannot create an instance of $modelClass", e)
  10.             }
  11.         }
复制代码
一个泛型方法返回一个自定义的viewmodel实例,但是还是没看到如何存储的viewmodel,别急
我们再来看最后调用的get方法
  1. @MainThread
  2.     public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
  3.         val viewModel = store[key]
  4.         if (modelClass.isInstance(viewModel)) {
  5.             (factory as? OnRequeryFactory)?.onRequery(viewModel)
  6.             return viewModel as T
  7.         } else {
  8.             @Suppress("ControlFlowWithEmptyBody")
  9.             if (viewModel != null) {
  10.                 // TODO: log a warning.
  11.             }
  12.         }
  13.         val extras = MutableCreationExtras(defaultCreationExtras)
  14.         extras[VIEW_MODEL_KEY] = key
  15.         // AGP has some desugaring issues associated with compileOnly dependencies so we need to
  16.         // fall back to the other create method to keep from crashing.
  17.         return try {
  18.             factory.create(modelClass, extras)
  19.         } catch (e: AbstractMethodError) {
  20.             factory.create(modelClass)
  21.         }.also { store.put(key, it) }
  22.     }
复制代码
首选会从ViewModelStore中获取viewmodel ,看if语句内部就可以看出直接返回的是缓存的viewmodel,如果不存在则根据创建的factory去实例化viewmodel然后并存储到ViewModelStore中。
经过我们的源码分析,我们现在已经明白了viewmodel的存储过程和如何在activity销毁时获取的流程。
那么viewmodel又是如何销毁的呢?还记得viewmodel中的onCleared方法吗?注释就写明了当这个ViewModel不再使用并被销毁时,这个方法将被调用。 那么就来看这个方法在什么时候调用的
内部有一个clear该方法又被ViewModelStore的clear方法调用,接着又被ComponentActivity内部
  1. getLifecycle().addObserver(new LifecycleEventObserver() {
  2.             @Override
  3.             public void onStateChanged(@NonNull LifecycleOwner source,
  4.                     @NonNull Lifecycle.Event event) {
  5.                 if (event == Lifecycle.Event.ON_DESTROY) {
  6.                     // Clear out the available context
  7.                     mContextAwareHelper.clearAvailableContext();
  8.                     // And clear the ViewModelStore
  9.                     if (!isChangingConfigurations()) {
  10.                         getViewModelStore().clear();
  11.                     }
  12.                 }
  13.             }
  14.         });
复制代码
用到了Lifecycle去监听生命周期当activity不正常销毁时,则清除掉缓存的viewmodel。至此我们就搞懂了viewmodel是如何实现了对数据的存储和以及数据的获取。
这里还有一点需要额外说明,ViewModelStore也是从缓存中取得, 在getViewModelStore方法和onRetainNonConfigurationInstance方法中 都能看到getLastNonConfigurationInstance方法的身影。不为null,就获取缓存的ViewModelStore,那就自然能获取到之前存储的viewModel 至于怎么缓存的各位大佬自己研究吧!
至此 ,我们已经搞懂了viewmodel是如何做到在activity销毁时自动清除和销毁重建显示之前数据。
到此这篇关于Android ViewModel的作用深入讲解的文章就介绍到这了,更多相关Android ViewModel内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:24
  • 打卡月天数:0
  • 打卡总奖励:310
  • 最近打卡:2025-04-14 11:31:20
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
349
积分
54
注册时间
2023-1-7
最后登录
2025-4-14

发表于 2023-7-26 21:45:04 | 显示全部楼层
感谢楼主分享~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2025-3-21 10:00:56 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表