Jetpack 之 ViewModel 组件介绍

简介: ViewModel 是介于 View(视图)和 Model(数据模型)之间的一个东西。它起到了桥梁的作用,使视图和数据既能够分离开,也能够保持通信。

本文目录

一、什么是 ViewModel

ViewModel 是介于 View(视图)和 Model(数据模型)之间的一个东西。它起到了桥梁的作用,使视图和数据既能够分离开,也能够保持通信。

ViewModel 将页面所需要的数据从页面中剥离出来,页面只需要处理用户交互和展示数据。

ViewModel 一般是通过 LiveData 或 DataBinding 两种方式来通知页面数据发生变化,更新 UI。关于 LiveData 和 DataBinding 我们在后面的文章会介绍,这里知道有这两种方式即可。

二、ViewModel 的生命周期

ViewModel 总是随着 Activity/Fragment 的创建而创建,随着 Activity/Fragment 的销毁而销毁。

不过,ViewModel 的生命周期是独立于配置变化的。如屏幕旋转所导致的 Activity 重建,并不会影响 ViewModel 的生命周期,重建后的 Activity 会重新连接到现有的 ViewModel。

Tips:配置变更主要是指:横竖屏切换、分辨率调整、权限变更、系统字体样式变更、启用多窗口模式...

三、ViewModel 的基本使用方法

步骤一:添加依赖

def lifecycle_version = "2.2.0"

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"

最新版本号请查看:LifeCycle

步骤二:自定义 TimerViewModel 类,继承 ViewModel

public class TimerViewModel extends ViewModel {
   
   

    /**
     * 清理资源
     */
    @Override
    protected void onCleared() {
   
   
        super.onCleared();
        timer.cancel();
    }
}

ViewModel 本身是一个抽象类,其中只有一个 onCleared 方法,当 ViewModel 不再被需要,即与之相关的 Activity 都被销毁时,系统会调用该方法。我们可以在该方法中执行一些资源释放的相关操作。

步骤三

前文提到,ViewModel 最重要的作用是将视图与数据分离,并独立于 Activity 的重建,为了验证这一点,我们在 ViewModel 中创建一个计时器 Timer,每隔 1s,通过接口 OnTimeChangeListener 通知它的调用者(实际上通过接口的方式通知不是很好,更好的方式是通过 LiveData 组件来实现)。

public class TimerViewModel extends ViewModel {
   
   
    private Timer timer;
    private int currentSecond;

    /**
     * 开始计时
     */
    public void startTiming() {
   
   
        if (timer == null) {
   
   
            currentSecond = 0;
            timer = new Timer();
            TimerTask timerTask = new TimerTask() {
   
   
                @Override
                public void run() {
   
   
                    currentSecond++;
                    if (onTimeChangeListener != null) {
   
   
                        onTimeChangeListener.onTimeChanged(currentSecond);
                    }
                }
            };
            timer.schedule(timerTask, 1000, 1000);
        }
    }

    /**
     * 通过接口的方式,完成对调用者的通知
     * 实际上这种方式不是很友好,更好的方式是通过LiveData组件来实现
     */
    public interface OnTimeChangeListener {
   
   
        void onTimeChanged(int second);
    }

    private OnTimeChangeListener onTimeChangeListener;

    public void setOnTimeChangeListener(OnTimeChangeListener onTimeChangeListener) {
   
   
        this.onTimeChangeListener = onTimeChangeListener;
    }

    /**
     * 清理资源
     */
    @Override
    protected void onCleared() {
   
   
        super.onCleared();
        timer.cancel();
    }
}

步骤四:在 TimerActivity 中监听 OnTimeChangeListener 发来的通知,并更新 UI。

ViewModel 的实例化过程,是通过 ViewModelProvider 来完成的。ViewModelProvider 会判断 ViewModel 是否存在,若存在直接返回,否则它会创建一个 ViewModel。

public class TimerActivity extends AppCompatActivity {
   
   
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);
        initComponent();
    }

    private void initComponent() {
   
   
        textView = findViewById(R.id.textView);
        TimerViewModel timerViewModel = new ViewModelProvider(this).get(TimerViewModel.class);
        timerViewModel.setOnTimeChangeListener(new TimerViewModel.OnTimeChangeListener() {
   
   
            @Override
            public void onTimeChanged(int second) {
   
   
                runOnUiThread(new Runnable() {
   
   
                    @Override
                    public void run() {
   
   
                        textView.setText("TIME:" + second);
                    }
                });
            }
        });
        timerViewModel.startTiming();
    }
}

步骤五:运行项目,并且旋转屏幕,看看计时器有没有停止

当旋转屏幕,Activity 重建时,计时器并没有停止。

四、ViewModel 与 AndroidViewModel

为了避免内存泄漏,我们在使用 ViewModel 时,不能将任何类型的 Context 或含有 Context 引用的对象传入 ViewModel。但是如果希望在 ViewModel 中使用 Context 的话该怎么办呢?

可以使用 AndroidViewModel ,它继承自 ViewModel,并接收 Application 作为 Context。

五、ViewModel 与 onSaveInstanceState() 对比

对于页面数据的保存和恢复,onSaveInstanceState() 方法同样可以解决屏幕旋转带来的数据丢失问题,那么我们是不是就没有必要使用 ViewModel 了呢?

注意,onSaveInstanceState() 方法只能保存少量的、能支持序列化的数据,而 ViewModel 没有这个限制,ViewModel 能支持页面中所有的数据。

同样需要注意的是,ViewModel 不支持数据的持久化,当界面被彻底销毁时,ViewModel 及其持有的数据就不存在了,但是 onSaveInstanceState() 方法没有这个限制,它可以持久化页面的数据。

可见,onSaveInstanceState() 方法有其特殊的用途,二者不可以混淆。

名称 保存数据的类型 是否支持持久化
ViewModel 只能保存少量的、能支持序列化的数据
onSaveInstanceState() 支持页面中所有的数据

六、使用 ViewModel 需要注意的地方

  1. ViewModel 的唯一职责是管理页面需要的数据(即 UI 需要的数据)。它不应该访问你的 View 结构,也不能持有 Activity/Fragment 的引用。
  2. 在使用 ViewModel 的过程中,千万不要将任何类型的 Context 或带有 Context 引用的对象传入 ViewModel ,因为这样做可能会引发内存泄漏。如果一定要在 ViewModel 中使用 Context,那么建议使用 ViewModel 的子类 AndroidViewModel。
相关文章
|
11天前
|
存储 设计模式 数据库
构建高效的安卓应用:探究Android Jetpack架构组件
【4月更文挑战第20天】 在移动开发的世界中,构建一个既高效又可维护的安卓应用是每个开发者追求的目标。随着Android Jetpack的推出,Google为开发者提供了一套高质量的库、工具和指南,以简化应用程序开发流程。本文将深入探讨Jetpack的核心组件之一——架构组件,并展示如何将其应用于实际项目中,以提升应用的响应性和稳定性。我们将通过分析这些组件的设计原则,以及它们如何协同工作,来揭示它们对于构建现代化安卓应用的重要性。
|
4月前
|
Android开发 开发者
什么是Android Jetpack,它包括哪些组件?
什么是Android Jetpack,它包括哪些组件?
42 0
|
4月前
|
前端开发 测试技术 API
Jetpack MVVM 七宗罪之六:ViewModel 接口暴露不合理
Jetpack MVVM 七宗罪之六:ViewModel 接口暴露不合理
45 0
|
4月前
|
XML 前端开发 IDE
在 Compose 中使用 Jetpack 组件库
在 Compose 中使用 Jetpack 组件库
88 0
|
8月前
|
安全 API Android开发
Jetpack架构组件库-Jetpack入门介绍
Jetpack架构组件库-Jetpack入门介绍
95 0
|
10天前
|
设计模式 前端开发 数据库
构建高效Android应用:使用Jetpack架构组件实现MVVM模式
【4月更文挑战第21天】 在移动开发领域,构建一个既健壮又易于维护的Android应用是每个开发者的目标。随着项目复杂度的增加,传统的MVP或MVC架构往往难以应对快速变化的市场需求和复杂的业务逻辑。本文将探讨如何利用Android Jetpack中的架构组件来实施MVVM(Model-View-ViewModel)设计模式,旨在提供一个更加模块化、可测试且易于管理的代码结构。通过具体案例分析,我们将展示如何使用LiveData, ViewModel, 和Repository来实现界面与业务逻辑的分离,以及如何利用Room数据库进行持久化存储。最终,你将获得一个响应迅速、可扩展且符合现代软件工
14 0
|
19天前
|
存储 数据库 Android开发
构建高效安卓应用:采用Jetpack架构组件优化用户体验
【4月更文挑战第12天】 在当今快速发展的数字时代,Android 应用程序的流畅性与响应速度对用户满意度至关重要。为提高应用性能并降低维护成本,开发者需寻求先进的技术解决方案。本文将探讨如何利用 Android Jetpack 中的架构组件 — 如 LiveData、ViewModel 和 Room — 来构建高质量的安卓应用。通过具体实施案例分析,我们将展示这些组件如何协同工作以实现数据持久化、界面与逻辑分离,以及确保数据的即时更新,从而优化用户体验并提升应用的可维护性和可测试性。
|
24天前
|
存储 SQL 数据库
构建高效Android应用:采用Jetpack架构组件的实践之路
【4月更文挑战第7天】 在快速迭代的移动开发领域,构建一个既健壮又易于维护的Android应用至关重要。本文将深入探讨如何利用Google推出的Jetpack架构组件,实现Android应用的模块化和组件化,从而提升开发效率和应用性能。我们将通过具体实例分析生命周期管理、UI控制器、数据存储等核心组件,展示其在真实应用中的运用,以及如何借助这些组件简化日常开发任务,确保代码的可扩展性和可测试性。
|
9月前
|
Android开发
Android JetPack组件之ViewModel状态的保存(程序在后台被系统杀死数据也存活)
Android JetPack组件之ViewModel状态的保存(程序在后台被系统杀死数据也存活)
100 0
|
9月前
|
Android开发
Android JetPack组件之DataBinding的使用详解
Android JetPack组件之DataBinding的使用详解
177 0