【Jetpack】ViewModel 架构组件 ( 视图 View 和 数据模型 Model | ViewModel 作用 | ViewModel 生命周期 | 代码示例 | 使用注意事项 )

news2025/2/24 0:27:58

文章目录

  • 一、Activity 遇到的问题
  • 二、视图 View 和 数据模型 Model
  • 三、ViewModel 架构组件作用
  • 四、ViewModel 代码示例
    • 1、ViewModel 视图模型
    • 2、Activity 组件
    • 3、UI 布局文件
    • 4、运行效果
  • 五、ViewModel 生命周期
  • 六、ViewModel 使用注意事项





一、Activity 遇到的问题



Activity 遇到的问题 :

  • 瞬态数据丢失 : 操作 Activity 时 , 如果 屏幕 自动旋转 , 当前 Activity 组件会 执行销毁操作 , 并重新创建新的 Activity 组件 , 该操作会 导致 Activity 的 瞬态数据 丢失 ;
  • 内存泄漏 : 在 系统组件 如 Activity 中 , 启动了一个线程 , 在线程中执行一系列操作 , 如果 Activity 在线程停止前销毁 , 那么 从 Activity 销毁 到 线程停止前 的这一段时间 , 就出现了内存泄漏问题 ;
  • 组件代码量大 : 在 Activity 中写了大量的代码 , 导致 可维护性 降低 , 测试难度 增加 ;




二、视图 View 和 数据模型 Model



在 Activity 中 , 存在两种元素 , 视图 View 和 填充视图数据用的 数据模型 Model ;

如果将 视图 和 数据模型 都写在 Activity 中 , 二者 耦合程度很高 ,

此时 , 就会造成上述 Activity 的三大问题 : ① 丢失瞬态数据 , ② 内存泄漏 , ③ 组件代码量大 ;





三、ViewModel 架构组件作用



为了解决上述问题 , 提出了 ViewModel 架构组件 ,

该组件 是 视图 View数据模型 Model 之间 的 沟通桥梁 ;

借助 ViewModel , 视图 与 数据模型 实现了 解耦 , 同时 还能保证 视图 与 数据模型 之间 保持 通信 ;

这样 Activity 的代码量减少了 , 只需要维护 视图 View 相关内容 , 增加了代码的可维护性 , 以及可测试性 ;

在这里插入图片描述

在 ViewModel 架构中 , 数据 不由 View 直接进行管理 , 而是 由 ViewModel 进行管理 ;

当 Activity 屏幕旋转 , 销毁时 , 只会销毁 Activity 组件 , 不会将 ViewModel 以及 数据模型 Model 销毁 ;

Activity 中的组件 获取数据时 , 不直接从 数据模型 Model 中获取 , 而是 从 ViewModel 架构组件中获取 ;


ViewModel 作用 :

  • 保存瞬态数据
  • 作为 View 视图 与 Model 数据模型 的桥梁
  • 作为 不同的 Activity 或 Fragment 之间沟通的桥梁




四、ViewModel 代码示例




1、ViewModel 视图模型


ViewModel 视图模型 继承 androidx.lifecycle.ViewModel 类 , 在其中定义要维护的数据即可 ;

代码示例 :

package kim.hsl.viewmodeldemo

import androidx.lifecycle.ViewModel

class MyViewModel : ViewModel() {
    var number: Int = 0
}

2、Activity 组件


在 Activity 中 , 要 绑定 ViewModel 组件 , 通过 ViewModelProvider 获取 MyViewModel::class.java 类 对应的 ViewModel 实例对象 ;

代码示例 :

package kim.hsl.viewmodeldemo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.lifecycle.ViewModelProvider

class MainActivity : AppCompatActivity() {

    lateinit var textView: TextView
    lateinit var myViewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 获取布局组件
        textView = findViewById(R.id.textView)

        // 获取 ViewModel
        myViewModel = ViewModelProvider(this,
            ViewModelProvider.AndroidViewModelFactory(application))
            .get(MyViewModel::class.java)

        // 组件中显示 ViewModel 中的内容
        textView.setText("${myViewModel.number}")
    }

    fun onClick(view: View) {
        myViewModel.number++
        textView.setText("${myViewModel.number}")
    }
}

3、UI 布局文件


点击按钮 , 令显示的文本数字自增 ;

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="40sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.3" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="数值自增"
        android:textSize="40sp"
        android:onClick="onClick"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.5" />

</androidx.constraintlayout.widget.ConstraintLayout>

4、运行效果


在屏幕旋转后 , Activity 销毁重建 , 也没有影响数据运行 , 自增操作没有被打断 ;

请添加图片描述





五、ViewModel 生命周期



ViewModel 的 生命周期Activity 或 Fragment 的 生命周期 相互独立 , ViewModel 不受 Activity 组件销毁的影响 ;

如果 由于 屏幕旋转 原因 导致的 Activity 销毁重建 , 与之绑定的 ViewModel 会在销毁时解绑 , Activity 重建时重新绑定 ;

ViewModel 会在 应用生命周期 内存活 , 并且可以在 Activity 或 Fragment 之间共享数据 ;

在这里插入图片描述


ViewModel 的 生命周期 : 一个 ViewModel 实例对象 可以与 多个 Activity 或 Fragment 绑定 ;

  • 创建 : 在 Activity 的 首次启动时 创建 ViewModel 实例对象 , 如果 Activity 多次启动 , ViewModel 只会创建一次 ;
  • 绑定 : Activity 与 ViewModel 关联时 , 开始绑定 ViewModel , Activity 组件中 绑定 ViewModel 代码如下 ;
        // 获取 ViewModel
        myViewModel = ViewModelProvider(this,
            ViewModelProvider.AndroidViewModelFactory(application))
            .get(MyViewModel::class.java)
  • 解绑 : 当 Activity 或者 Fragment 被销毁时 , 与之绑定的 ViewModel 会与 UI 组件解绑 ;
  • 销毁 : ViewModel 关联的所有的 Activity 或 Fragment 全部销毁 , 则 ViewModel 实例对象 也会被销毁 ;




六、ViewModel 使用注意事项



ViewModel 使用注意事项 :

使用 ViewModel 时 , 不要将 Context 上下文对象传入 ViewModel 中 , 否则会导致内存泄漏 ;

如果要使用 Context 上下文对象 , 则 ViewModel 需要继承 AndroidViewModel 类 , 在 其构造函数 中获取 Application 对象 ;


代码示例 :

package kim.hsl.viewmodeldemo

import android.app.Application
import androidx.lifecycle.AndroidViewModel

class MyViewModel2 : AndroidViewModel {
    constructor(application: Application) : super(application) {
        // 此处可获取 Application 上下文对象
    }
}

博客代码 :

  • GitHub : https://github.com/han1202012/ViewModelDemo
  • CSDN : https://download.csdn.net/download/han1202012/87541442

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

宝塔部署nodejs项目

前言 部署操作很简单&#xff0c;网上也有很多教程&#xff0c;不过我还是踩坑了&#xff0c;这里记录一下&#xff0c;给其他人也避避坑吧。 步骤 首先你已经有了服务器&#xff0c;并且打开了宝塔面板&#xff0c;其次准备好你的nodejs项目。 在宝塔安装pm2管理器&#xf…

Nginx 调整文件上传大小限制

使用3A服务器做了网页&#xff0c;感觉挺不错的&#xff0c;使用LNMP环境 用Nginx部署了前端&#xff0c;发现上传附件大一点就会报错&#xff0c;查看配置文件&#xff0c;发现spring的附件配置已经配置了。那么就看下Nginx的body设置。nginx文件上传默认是1MB。 在 server 模…

VUE3TS: Vue3+TS的项目搭建

简介 通过 Vue-cli4 创建的 Vue3TS 的项目&#xff0c;并进行一些基础使用的举例。 此例是以 VSCode编辑器 进行的编码。 一、项目搭建 1. 进入命令提示符窗口 在要搭建项目的文件夹中&#xff0c;点击路径&#xff0c;输入CMD并按回车 2. 查看node版本、Vue-cli版本 2…

Android 架构之长连接技术

上文中我们提到了HttpDNS&#xff0c;虽然它比系统DNS更优&#xff0c;但终归还是要做DNS操作。而长连接都是IP直接连接&#xff0c;因此没有DNS相关的开销和耗时。 3. 如果有大量网络请求&#xff0c;可以明显减少网络延时&#xff0c;节省带宽 对于大型App而言&#xff0c;…

npm——安装、卸载与更新

npm 官方文档&#xff1a;https://docs.npmjs.com/ 什么是npm npm&#xff08;“Node 包管理器”&#xff09;是 JavaScript 运行时 Node.js 的默认程序包管理器。 它也被称为“Ninja Pumpkin Mutants”&#xff0c;“Nonprofit Pizza Makers”&#xff0c;以及许多其他随机…

Vue通知提醒框(Notification)

项目相关依赖版本信息 可自定义设置以下属性&#xff1a; 自动关闭的延时时长&#xff08;duration&#xff09;&#xff0c;单位ms&#xff0c;默认4500ms消息从顶部弹出时&#xff0c;距离顶部的位置&#xff08;top&#xff09;&#xff0c;单位像素px&#xff0c;默认24p…

WebSocket开发(心跳监测)功能

前言 在之前的文章中完成了客服对话的Demo功能&#xff0c;但是现在的连接是无限制的长时间连接没有做心跳、失活、超时断连等功能&#xff0c;心跳的实现方法有很多种&#xff0c;并且WebSocket就提供了ping/pong类型的消息。 心跳的触发方式也分两种&#xff1a; 客户端触…

微信小程序实现图片上传

前言 手机上传图片的功能大家一定都用过吧&#xff0c;今天教你用微信小程序实现这个小功能。 实现效果如下&#xff1a; 实现思路&#xff1a; 首先我们需要定义一个存放图片的数组&#xff0c;通过方法拿取图片的详细信息&#xff0c;然后调用微信小程序的 wx.uploadFile 方…

element ui datepicker时间控件实现范围选择周,季,年。

因项目要求&#xff0c;需日&#xff0c;周&#xff0c;月&#xff0c;季&#xff0c;年五种日期范围选择器&#xff0c;故参考文章&#xff08;在末尾&#xff09;后分享 一.效果图 二、版本及下载 1.实现需要修改源码&#xff0c;目前修改的版本为2.15.3&#xff0c;所以想要…

Vue3路由配置createRouter、createWebHistory、useRouter,useRoute

目录 手动配置Vue-router环境&#xff1a; 组件内部跳转路由、传参useRouter,useRoute Vue3和Vue2基本差不多&#xff0c;只不过需要将createRouter、createWebHistory从vue-router中引入&#xff0c;再进行使用。 手动配置Vue-router环境&#xff1a; 1、下载包&#xff1a…

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘result‘)

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading result) 如题所示问题&#xff0c;耽误三天寻找bug&#xff0c;终于在我睡意朦胧之际发现了一道光&#xff0c;发现 await 出现的三个点&#xff1a; 于是打开 findAllCategory()这个函数 对应…

电商后台管理系统简介

项目介绍 黑马后台管理系统是一个电商后台管理系统的前端项目&#xff0c;基于VueElement实现。 主要包括商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等功能 开发技术 此项目开发我用到的技术有&#xff1a;vue2node.…

Vant 2 - 移动端 Vue 组件库 _ 问题记录

目录 Popup 弹出层 DatetimePicker 时间选择 Field 输入框 Picker 选择器 List 列表 Tab 标签页 发布初衷 &#xff1a; 记录在移动端项目中使用 Vant 2 组件库时遇到的各种问题 &#xff0c; 方便以后再次遇到类似问题 &#xff0c; 能够快时查阅解决 &#xff0c; …

Vue3+TypeScript+Vite如何使用require动态引入类似于图片等静态资源

问题&#xff1a;Vue3TypeScriptVite的项目中如何使用require动态引入类似于图片等静态资源&#xff01; 描述&#xff1a;今天在开发项目时&#xff08;项目框架为Vue3TypeScriptVite&#xff09;需要 动态引入静态资源&#xff0c;也就是img标签的src属性值为动态获取&#…

Lodash 使用及常用方法

简介 Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。它内部封装了诸多对字符串、数组、对象等常见数据类型的处理函数,Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。 官网 Lodash 简介 | Lodash 中文文档…

TypeScript详解十六:类型声明(declare)

目录前言一、类型声明的作用&#xff1f;1.1 declare 关键字1.2 示例二、常见的几种类型声明2.1 普通类型声明2.2 外部枚举2.3 命名空间三、类型声明文件3.1 模拟类型声明文件&#xff0c;以 jquery 为例3.2 使用手动实现的jquery.d.ts声明文件3.3 第三方声明文件&#xff08;以…

Django web 开发(三) - Django的使用

文章目录Django安装Django安装Pythonpip加速安装Django创建项目文件介绍简单访问APP添加新的app注册app创建blog的页面templates模板templates模板语法单一变量列表循环(列表)字典循环(字典)列表套字典条件判断请求和响应案例: 用户登录数据库操作安装第三方模块ORM创建数据库D…

node版本、npm版本随意切换

前言 随着项目越做越多&#xff0c;难免会有a项目需要12.x的node版本&#xff0c;b项目需要>16.0.0的情况。 为了避免出现node版本切换的繁琐&#xff0c;特意找了这么一个工具&#xff0c;主要是方便管理node版本。 请按照以下步骤来实现 官方地址: 传送门 1、下载软件 …

使用react实现后台管理系统项目

一.开发React必须依赖三个库 1.react&#xff1a;包含react所必须的核心代码 2.react-dom&#xff1a;react渲染在不同平台所需要的核心代码 3.babel&#xff1a;将jsx转换成React代码的工具 二.React的依赖引入 1.方式一&#xff1a;直接CDN引入 2.方式二&#xff1a;下载后&…

vue高级特性总结

文章目录一、修饰符1、事件修饰符案例1案例22、按键修饰符案例33、表单修饰符案例4二、计算属性computed案例5三、监听器watch案例6案例7&#xff1a;当商品数量大于1000时&#xff0c;输入框中数字自动设置成1000&#xff1b;当商品数量小于0时&#xff0c;输入框中数字自动设…