JetPack组件学习ViewModel

简介: JetPack组件学习ViewModel

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都有回调,可以做自定义处理


目录
相关文章
|
7月前
|
存储 设计模式 数据库
构建高效的安卓应用:探究Android Jetpack架构组件
【4月更文挑战第20天】 在移动开发的世界中,构建一个既高效又可维护的安卓应用是每个开发者追求的目标。随着Android Jetpack的推出,Google为开发者提供了一套高质量的库、工具和指南,以简化应用程序开发流程。本文将深入探讨Jetpack的核心组件之一——架构组件,并展示如何将其应用于实际项目中,以提升应用的响应性和稳定性。我们将通过分析这些组件的设计原则,以及它们如何协同工作,来揭示它们对于构建现代化安卓应用的重要性。
|
7月前
|
Android开发 开发者
什么是Android Jetpack,它包括哪些组件?
什么是Android Jetpack,它包括哪些组件?
245 0
|
7月前
|
前端开发 测试技术 API
Jetpack MVVM 七宗罪之六:ViewModel 接口暴露不合理
Jetpack MVVM 七宗罪之六:ViewModel 接口暴露不合理
91 0
|
7月前
|
XML 前端开发 IDE
在 Compose 中使用 Jetpack 组件库
在 Compose 中使用 Jetpack 组件库
383 0
|
前端开发 Android开发
Jetpack Compose 学习指南(二)
Jetpack Compose 学习指南(二)
175 0
|
安全 API Android开发
Jetpack架构组件库-Jetpack入门介绍
Jetpack架构组件库-Jetpack入门介绍
154 0
|
2月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
52 6
|
6月前
|
JavaScript Java Android开发
kotlin安卓在Jetpack Compose 框架下跨组件通讯EventBus
**EventBus** 是一个Android事件总线库,简化组件间通信。要使用它,首先在Gradle中添加依赖`implementation &#39;org.greenrobot:eventbus:3.3.1&#39;`。然后,可选地定义事件类如`MessageEvent`。在活动或Fragment的`onCreate`中注册订阅者,在`onDestroy`中反注册。通过`@Subscribe`注解方法处理事件,如`onMessageEvent`。发送事件使用`EventBus.getDefault().post()`。
|
5月前
|
XML 存储 API
Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging
Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging
|
7月前
|
前端开发 Android开发
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)