JetPack组件学习ViewModel
1.需要先创建ViewModel类 继承自ViewModel重写onclear方法 使得页面销毁的时候能够走到自定义的onClear方法中
class MyViewModel : ViewModel() { //共享数据的核心在于拿到同一个LiveData实例 也就是拿到同一个ViewModel实例 其保存在ViewModelStore中 //而ViewModelStore是Activity/Fragment提供的 做了屏幕转换的恢复处理 ViewModelStore会保存其数据 var progress:MutableLiveData Int ? null override fun onCleared() { //页面销毁回调 super.onCleared() Log.i( wwwwwwwwwwwwwwwww , onCleared:MyVBiewModel cleared ) }
2 创建ViewModelProvider
在Activity中创建ViewModelProvider实例需要ViewModelOwner作为参数
和LifeCyclerOwner一样都是CommpentActivity实现的接口
除此之外还需要一个工厂。
该工厂默认实现是获取get函数传入的class反射创建ViewModel实例 也可以自定义工厂函数 会接受一个class的参数只需要返回该实例即可 中间的操作可以自定义
一 传入ViewModelOwner Activity/Fragment已经实现该接口 ViewModelProvider(this) .get(MyViewModel::class.java) //默认实现反射创建ViewModel实例 二 创建实例过程自定义返回ViewModel实例即可 ViewModelProvider(this,object :ViewModelProvider.Factory{ override fun T : ViewModel? create(modelClass: Class T ): T { modelClass.constructors return modelClass.getConstructor(Application::class.java).newInstance(application) }).get(RoomViewModel::class.java).
上面是利用反射创建了一个带有参数的ViewModel。默认创建的是无参的实例
3.通过get传入对应的Viewmodel的Class对象即可。
简要分析首先创建ViewModelProvider实例 看下对应源码
public ViewModelProvider( NonNull ViewModelStoreOwner owner, NonNull Factory factory) { //第一个参数调用其getViewModelStore函数 //第二个参数是个工厂稍后分析 this(owner.getViewModelStore(), factory); }
可以看到Fragment和ComponentActivity都实现了该接口
接下来查看ComponentActivity。
1.首次mViewModelStore肯定为null 从nc中取出肯定也取不到只能通过new的方式去创建
2.当经历了屏幕旋转这时候就会从configure中取出viewmodelStore了 对应的也就是第二个红框 最后说明这个流程。
创建完ViewModelProvider后 调用get方法获取Viewmodel实例。
private static final String DEFAULT_KEY androidx.lifecycle.ViewModelProvider.DefaultKey public T extends ViewModel T get( NonNull Class T modelClass) { String canonicalName modelClass.getCanonicalName(); if (canonicalName null) { throw new IllegalArgumentException( Local and anonymous classes can not be ViewModels //传入两个参数 //第一个是之后做缓存用的 DEFAULT_KEY 是常量 //第二个是自定义ViewModel的class return get(DEFAULT_KEY : canonicalName, modelClass); }
NonNull MainThread public T extends ViewModel T get( NonNull String key, NonNull Class T modelClass) { //首先从缓存中获取 viewmodelStore可以看成是一个map 保存ViewModel ViewModel viewModel mViewModelStore.get(key); //可以看到mFactory 分为两类 1.OnRequeryFactory 当缓存命中后该方法会回调并将命中的viewmodel传入 2.KeyedFactory 继承自OnRequeryFactory 并提供create函数提供class创建实例过程有用户自定义 if (modelClass.isInstance(viewModel)) { //OnRequeryFactory是缓存命中后的回调 if (mFactory instanceof OnRequeryFactory) { ((OnRequeryFactory) mFactory).onRequery(viewModel); return (T) viewModel; } else { //noinspection StatementWithEmptyBody if (viewModel ! null) { // TODO: log a warning. //调用create函数将class传入 内部使用不同的构造方法创建实例并返回 if (mFactory instanceof KeyedFactory) { viewModel ((KeyedFactory) (mFactory)).create(key, modelClass); } else { viewModel (mFactory).create(modelClass); //缓存该ViewModel mViewModelStore.put(key, viewModel); return (T) viewModel; }
ViewModelStore源码
public class ViewModelStore { //可以看到就是个map缓存 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()); * Clears internal storage and notifies ViewModels that they are no longer used. public final void clear() { for (ViewModel vm : mMap.values()) { vm.clear(); mMap.clear(); }问答如何实现旋转屏幕数据保持不变
答 1.第一次创建 首先会从对应的Activity中的NoLastConfigure获取activity取出对应的ViewModelStore这个时候由于是第一次所以是null 于是只能new一个ViewModelStore。
2.Activity重建时会销毁页面将ViewmodelStore保存到lastCongiure中并保存到ActivityClientRecord中传递给AMS端。
3.AMS重新调用 这里需要注意如果是配置引起的重建会走RelauchActivity而不是第一次普通的lauchActivity ReLaunch会通过token取出对应的AcRecord 在attach的时候将record中上一次保存的lastCoinfigure取出来
4.onCreate的时候把store赋值给NoLastConfigure 这个时候页面执行onCreate获取 ViewModelStore就可以获取到了 而且Store是保存着这个页面的所有Viewmodel所以上一次的ViewModel中的数据还在并没有销毁
详细流程
HandlerRelauncherActivity中先调用handlerdestory销毁页面保存重要配置到record中 AMS会保存token{Activity唯一标识}和record的map
在调用lauchActivity重建页面通过token重新取出record record在取出configure保存到新创建的activity的属性中。
1.当调用performDestory的时候创建一个Configure类取出viewmodelStore中如果没有直接取到从上一次的configure中取 创建完configure后保存
到record中的lastConfigure属性中。
2.何时重建 在performLaunchActivity方法中调用attach方法 在这个方法中取出record中的lastConfigure赋值给成员变量mLastConfigure
和之前的Presenter有什么区别个人感觉
1.持有V层引用这个很好地解决了 但是回调V层还是得利用很多接口进行传递数据 这种主动通知V层的方式虽然变成接口回调的方式本质上耦合还是严重 可以通过LiveData V层去观察ViewModel中的数据变化这样耦合会降低一些
2.当配置失效比如屏幕旋转会销毁重建Activity 数据虽说可以通过onSavedInstance来传递 但是数据量并不能太大。但是ViewModel是系统原生支持的我们可以直接获取到上次销毁的ViewModel实例数据还在其中
3.具有生命周期可以自动管理防止泄漏 可通过onCleared告知持有该ViewModel的V层销毁
4.缓存命中和创建Viewodel都有回调 可以做自定义处理
Android Jetpack系列之ViewModel ViewModel的定义:**ViewModel旨在以注重生命周期的方式存储和管理界面相关的数据**。ViewModel本质上是视图(View)与数据(Model)之间的桥梁,想想以前的MVC模式,视图和数据都会写在Activity/Fragment中,导致Activity/Fragment过重,后续难以维护,而ViewModel将视图和数据进行了分离解耦,为视图层提供数据。
大放光彩的安卓Jetpack组件-ViewModel(终) 前面我们已经说过Jetpack中ViewModel的作用、用法以及使用要点,但还缺少在Activity中的实例展示,所以本节我们将结合结果展示与代码进行解读,希望能更好的展示出ViewModel的风采。
大放光彩的安卓Jetpack组件-ViewModel(二) 上回我们说到使用方法,但没有具体去说明使用的要点,其实ViewMode还是挺容易上手的,这节我们来具体说明一些使用要点与运用方式。
相关文章
- Android Jetpack组件 Compose 使用介绍
- Android Jetpack组件 DataStore的使用和简单封装
- Android Jetpack架构开发,从入门到实战,看这一篇就够了
- Android Jetpack Compose最全上手指南,你学会了吗?
- Jetpack系列-ViewModel的使用及原理浅析
- 送你一份 Android Jetpack 架构入门秘籍,从入门到强化实战
- Android Jetpack系列--1.Lifecycle使用及源码解析
- Android Jetpack组件之Lifecycles库详解
- Android Jetpack组件 - ViewModel,LiveData使用以及原理
- Android 工程师编写的 SwiftUI 与 Jetpack Compose深度对比
- Jetpack Compose 教程:如何使用 FlowLayout
- 探索 Android Jetpack Compose
- Jetpack Compose 声明式 UI入门简介
- Jetpack Compose教程之 被动视图 让你的 UI 代码简单而愚蠢
- Jetpack Compose教程之 Jetpack Compose 核心功能介绍
- Jetpack Compose教程之 为什么 Jetpack Compose 不像看起来那么容易?
- 超级简洁、彻底组件化的轻量级Android Kotlin Jetpack MVVM组件化框架
- Jetpack Compose之线性布局和帧布局
- Jetpack太香了,让开发效率提升了不少
- 如何在 Jetpack Compose 中调试重组
- 一起看 I/O | Jetpack Compose 中的新特性
- 让你易上手的Jetpack Compose教程:帮你写出漂亮的小组件-Jetpack Glance
- Android Jetpack-ViewModel
- Jetpack Composes 【01】
- Jetpack架构组件(二)Lifecycle使用
- 带你了解Android Jetpack