Android ViewModel深入解析

昨天 8111阅读 0评论

ViewModel

  • ViewModel介绍(官网介绍)
  • ViewModel的优势
    • 1、代码分离
    • 2、数据绑定:
    • 3、易于测试
    • 4、生命周期管理
    • 5、数据共享
    • ViewModel是如何实现?
      • 1、ViewModel生命周期
        • 1、ViewModel是如何创建的?
        • 2、ViewModel是什么时候销毁的?
        • 2、ViewModel如何实现数据持久化?

          ViewModel介绍(官网介绍)

          ViewModel 类是一种业务逻辑或屏幕级状态容器。它用于将状态公开给界面,以及封装相关的业务逻辑。 它的主要优点是,它可以缓存状态,并可在配置更改后持久保留相应状态。这意味着在 activity 之间导航时或进行配置更改后(例如旋转屏幕时),界面将无需重新提取数据。

          注意:AndroidX以后才能使用ViewModel

          ViewModel的优势

          个人觉得ViewModel的出现给我们带来了以下几点便利:

          1、代码分离

          • ViewModel使得UI和业务逻辑分离。这意味着UI代码(如XML布局)专注于显示信息,而ViewModel则处理数据获取、验证和转换。这种分离使得代码更易于阅读和维护。

            2、数据绑定:

            • ViewModel通常与LiveData一起使用,这意味着当ViewModel中的数据发生变化时,UI会自动更新。这减少了手动更新UI的需要,降低了出错的可能性。

              3、易于测试

              • 由于ViewModel包含业务逻辑,因此可以独立于UI进行测试。这有助于确保你的应用程序在更改UI或添加新功能时仍然正常工作。

                4、生命周期管理

                • ViewModel + LiveData可以管理数据的生命周期,确保在适当的时候加载和保存数据。这有助于减少资源消耗并提高应用程序的性能。

                  5、数据共享

                  多个Fragment可以共享同一个ViewModel,这使得在多个Fragment之间共享数据变得更加简单和高效

                  ViewModel是如何实现?

                  看源码前,我们先大概了解这几个类是干什么的?

                  • ViewModel:

                    这是ViewModel的基类,它提供了基本的生命周期感知功能。ViewModel内部使用了一个Handler来处理UI线程与后台线程之间的通信,确保数据更新在UI线程进行。

                  • ViewModelProvider:

                    这个类负责创建和提供ViewModel的实例。它根据请求的ViewModel类型来创建或查找已经存在的实例,并将其与LifecycleOwner(通常是Activity或Fragment)关联起来。

                  • ViewModelStore:

                    ViewModelStore是一个内部类,用于存储和管理ViewModel的实例。它确保每个LifecycleOwner都有一个唯一的ViewModel实例。

                    我们将从ViewModel的生命周期和ViewModel是如何实现数据持久化这两个角度分析。

                    1、ViewModel生命周期

                    Android ViewModel深入解析 第1张

                    从上述图中,我们可以看到当我们acivity正常destroy我们的ViewModel才会正常销毁。

                    1、ViewModel是如何创建的?

                    我们一般通过ViewModelProvider获取ViewModel

                    //传入类名获取ViewModel
                    mViewModel = ViewModelProvider(this).get(MainViewModel::class.java) 
                    
                    @NonNull
                    @MainThread
                    public  T get(@NonNull Class modelClass) {
                    	//获取canonicalName,这里面其中包含类名和包的路径
                        String canonicalName = modelClass.getCanonicalName();
                        if (canonicalName == null) {
                            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
                        }
                        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
                    }
                    @NonNull
                    @MainThread
                    public  T get(@NonNull String key, @NonNull Class modelClass) {
                        ViewModel viewModel = mViewModelStore.get(key);
                        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.
                            }
                        }
                        if (mFactory instanceof KeyedFactory) {
                            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
                        } else {
                        	//没有获取到的时候通过mFactory创建ViewModel
                            viewModel = mFactory.create(modelClass);
                        }
                        //将创建的ViewModel存入mViewwModelStore
                        mViewModelStore.put(key, viewModel);
                        return (T) viewModel;
                    }
                    

                    1、创建viewModel实例

                    Android ViewModel深入解析 第2张

                    2、将ViewModel传入mViewModelStore

                    Android ViewModel深入解析 第3张

                    从上面代码可以看到,ViewModelStore会将viewModel和key放到一个HashMap去存放。

                    viewModelStore是哪里来的呢?

                    先看看下面代码

                    Android ViewModel深入解析 第4张

                    viewModelStore是一个关于activity的静态变量,可以看到通常每个Activity或Fragment都有自己的ViewModelStore,这是为了确保每个组件都有自己的ViewModel实例,从而保持其数据状态的独立性。

                    然而,如果有特殊需求,你可以通过一些方法让两个Activity共享同一个ViewModelStore,如以下代码。

                    class SharedViewModelStore {  
                        private val viewModelStore = ViewModelStore()  
                          
                        fun getViewModelStore(): ViewModelStore {  
                            return viewModelStore  
                        }  
                    }
                    class ActivityA : AppCompatActivity() {  
                          
                        private val sharedViewModelStore = SharedViewModelStore.getViewModelStore()  
                        private val myViewModel: MyViewModel by viewModels {  
                            MyViewModelFactory(application, sharedViewModelStore)  
                        }  
                          
                        // ...  
                    }  
                      
                    class ActivityB : AppCompatActivity() {  
                          
                        private val sharedViewModelStore = SharedViewModelStore.getViewModelStore()  
                        private val myViewModel: MyViewModel by viewModels {  
                            MyViewModelFactory(application, sharedViewModelStore)  
                        }  
                          
                        // ...  
                    }
                    

                    2、ViewModel是什么时候销毁的?

                    大家都知道ViewModel在Activity在onDestroy的时候会销毁,那么有个问题,在屏幕旋转的时候也会走onDestroy方法,为什么旋转的时候就不会销毁ViewModel呢?

                        public ComponentActivity() {
                    		...
                            getLifecycle().addObserver(new LifecycleEventObserver() {
                                @Override
                                public void onStateChanged(@NonNull LifecycleOwner source,
                                        @NonNull Lifecycle.Event event) {
                                    if (event == Lifecycle.Event.ON_DESTROY) {
                                    	//这个就是关键所在,判断是否正常销毁,还是改变配置. 如果是正常销毁则会把ViewModelStore的viewModel给销毁掉
                                        if (!isChangingConfigurations()) {
                                            getViewModelStore().clear();
                                        }
                                    }
                                }
                            });
                    		...
                        }
                    

                    2、ViewModel如何实现数据持久化?

                    当屏幕发生旋转的时候,会走到这个onRetainNonConfigurationInstance函数。

                        @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;
                        }
                    	...
                    	//调用新实例,允许您提取来自上一个实例的任何有用的动态状态。
                    	@Nullable
                        public Object getLastNonConfigurationInstance() {
                            return mLastNonConfigurationInstances != null
                                    ? mLastNonConfigurationInstances.activity : null;
                        }
                    

                    上述代码看出,当屏幕旋转后,会从NonConfigurationInstances 获取viewModelStore,当获取不到的时候再新建一个新的ViewModelStore.

                    那么这个mLastNonConfigurationInstances 是什么时候开始赋值的呢?

                        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
                        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,
                                IBinder shareableActivityToken) {
                            attachBaseContext(context);
                            ...
                            //在activity的attach的时候开始赋值
                            mLastNonConfigurationInstances = lastNonConfigurationInstances;
                            if (voiceInteractor != null) {
                                if (lastNonConfigurationInstances != null) {
                                    mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
                                } else {
                                    mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                                            Looper.myLooper());
                                }
                            }
                    		...
                        }
                    

                    mLastNonConfigurationInstances 的获取我们看到了,但是我们实际上想要的是viewModelStore。我们的ViewModelStore是在哪里开始获取呢?

                    让我们看看下面代码,代码中自有答案。

                        @Override
                        @Nullable
                        public final Object onRetainNonConfigurationInstance() {
                            Object custom = onRetainCustomNonConfigurationInstance();
                            ViewModelStore viewModelStore = mViewModelStore;
                            if (viewModelStore == null) {
                                // No one called getViewModelStore(), so see if there was an existing
                                // ViewModelStore from our last NonConfigurationInstance
                                //没有人调用getViewModelStore(),所以看看我们上一个NonConfigurationInstance中是否有现有的ViewModelStore
                                NonConfigurationInstances nc =
                                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                                if (nc != null) {
                                    viewModelStore = nc.viewModelStore;
                                }
                            }
                            if (viewModelStore == null && custom == null) {
                                return null;
                            }
                            NonConfigurationInstances nci = new NonConfigurationInstances();
                            nci.custom = custom;
                            nci.viewModelStore = viewModelStore;
                            return nci;
                        }
                    

                    这里就是ViewModelStore赋值的时候。

                    那么我们再问 这个是onRetainNonConfigurationInstance是什么时候开始调用呢?

                    onRetainNonConfigurationInstance在Activity的onDestroy的时候会被调用。

                    public final class ActivityThread{
                        @Override
                        public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
                                boolean getNonConfigInstance, String reason) {
                            //调用performDestroyActivity()方法    
                            ActivityClientRecord r = performDestroyActivity(token, finishing,
                                    configChanges, getNonConfigInstance, reason);
                            ...        
                        } 
                    }
                    

                    总结:

                    存储 ViewModel

                    • 创建 ViewModelStore:当Activity或Fragment被创建时,它们的ViewModelStore实例也会被创建。
                    • 获取 ViewModel:使用ViewModelProvider和ViewModelStore来获取ViewModel实例。如果ViewModel不存在,则会被创建并存储在ViewModelStore中。
                    • 使用 ViewModel:在Activity或Fragment中使用ViewModel来管理数据。
                    • 配置更改时的处理

                      • 销毁 Activity:当发生配置更改时(如屏幕旋转),当前的Activity实例会被销毁。
                      • 保存 ViewModelStore:在Activity销毁之前,它的ViewModelStore会被保存。这个保存过程涉及到多个层次:

                        ComponentActivity将ViewModelStore存入其NonConfigurationInstances。

                        Activity将ComponentActivity的NonConfigurationInstances(包含ViewModelStore)存入其自己的NonConfigurationInstances。

                        Activity的NonConfigurationInstances被存入ActivityClientRecord。

                        ActivityClientRecord被存入ActivityThread的mActivities ArrayMap中。

                      • 恢复 ViewModel重建 Activity:配置更改后,一个新的Activity实例会被创建。
                      • 恢复 ViewModelStore:当新的Activity实例被创建时,它会通过调用attach()方法并传入与旧Activity相同的ActivityClientRecord来恢复其ViewModelStore。
                      • 获取已存在的ViewModel:新的Activity实例使用ViewModelProvider和恢复的ViewModelStore来获取已存在的ViewModel实例。由于ViewModelStore中已经存在该ViewModel实例,因此它会被返回而不是创建新的实例。
                      • 恢复 ViewModel 的状态:由于ViewModel实例没有被销毁,因此它管理的数据状态也会被恢复。
                      • 销毁时的处理:当Activity或Fragment最终被销毁时(例如用户按下返回键或系统资源紧张),它们的ViewModelStore也会被销毁。然而,由于ViewModel的生命周期与ViewModelStore分离,ViewModel实例本身不会被销毁,除非没有Activity或Fragment引用它。

免责声明
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明。
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所
提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何
损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在
转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并白负版权等法律责任。

手机扫描二维码访问

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,8111人围观)

还没有评论,来说两句吧...

目录[+]