第13天:高级主题 - ViewModel 和 LiveData

在第13天,我们将深入学习Android的两个重要组件:ViewModelLiveData,并通过一个实践实例来学习如何应用它们。这些组件是 Android Jetpack 的一部分,它们不仅能让应用更具响应性和可扩展性,还能帮助你在面对配置变化(例如屏幕旋转)时保存数据,防止数据丢失。

##本节对应的代码链接为: TodoApp简单的待办事项(Todo)应用


1. ViewModel 和 LiveData 详细介绍

什么是 ViewModel?

ViewModel 是一种专门用于保存和管理 UI 相关数据的类,它解决了一个常见问题:当Activity或Fragment在配置发生变化(例如屏幕旋转)时会被销毁和重新创建,这可能导致其中的数据丢失。而 ViewModel 能够在这种情况下保持数据持久化,避免不必要的数据重新加载。

ViewModel 的作用主要包括:

  • 数据持久化:当Activity/Fragment重新创建时,ViewModel 中的数据仍然可以被保留,不会因为UI组件的重建而丢失。
  • 与生命周期分离ViewModel 独立于Activity或Fragment的生命周期。这意味着,即使Activity被销毁,ViewModel 中的数据也不会受到影响。
  • 数据管理ViewModel 是专门用于管理和处理与UI相关的数据逻辑,而不会影响UI的渲染逻辑。

举例来说,假设我们有一个任务列表应用,任务数据存储在 ViewModel 中。如果用户旋转屏幕,Activity 会重新创建,但 ViewModel 中的数据不会丢失,从而避免重新加载任务列表的操作。

什么是 LiveData?

LiveData 是一种可观察的数据持有类。与普通的数据类不同,LiveData 可以与UI组件建立联系,当数据发生变化时,UI组件会自动更新,无需手动通知。

LiveData 的主要特点包括:

  • 感知生命周期LiveData 会自动感知 ActivityFragment 的生命周期,并只在生命周期处于活跃状态时更新数据。当 Activity 被销毁或停止时,LiveData 会停止向UI发送更新,以避免内存泄漏。
  • 数据同步更新:当 LiveData 中的数据发生变化时,UI会自动更新,无需手动调用 notifyDataSetChangedinvalidate 等方法。
  • 无需手动管理生命周期LiveData 会自动处理与生命周期的绑定,使得我们不需要在代码中显式地管理数据和生命周期之间的关系。
MVVM 架构模式

在Android开发中,MVVM (Model-View-ViewModel)是一种常见的架构模式,能够使代码结构更清晰、可维护性更高。

  • Model(模型):负责数据的获取、存储以及业务逻辑的处理。它可以是来自网络、数据库或本地存储的数据。
  • View(视图):表示UI层,直接与用户进行交互。Activity 或 Fragment 通常扮演 View 的角色。
  • ViewModel:持有和管理与UI相关的数据逻辑。它不会直接与View打交道,而是通过 LiveData 来通知 View 更新。

这个模式能够很好地分离业务逻辑与UI逻辑,使代码更加模块化和易于维护。


2. 实践实例 - 构建一个待办事项应用

在这一部分,我们将通过Kotlin编写一个待办事项应用,演示如何使用 ViewModelLiveData 进行数据管理。这个应用的功能包括:展示任务列表,添加任务,并在任务列表中实时更新UI。


工程创建过程
  1. 创建新项目

    • 打开Android Studio,点击“New Project”。
    • 选择“Empty Activity”模板,并点击“Next”。
    • 设置项目名称为 TodoApp
    • 语言选择 Kotlin,点击“Finish”完成项目创建。
  2. 配置依赖
    在项目的 build.gradle 文件中,添加以下依赖,以确保我们可以使用 ViewModelLiveData

    dependencies {// ViewModel 和 LiveDataimplementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0"implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.0"// RecyclerView 用于展示任务列表implementation "androidx.recyclerview:recyclerview:1.2.1"
    }
    

    添加完依赖后,点击“Sync Now”同步项目。


3. MVVM 实现步骤

Step 1: 创建数据模型

首先,我们创建一个 Task 数据类,表示每个待办事项的任务。它包含三个属性:任务的唯一ID、任务名称和任务是否已完成的状态。

// Task.kt
data class Task(val id: Int,val name: String,val isCompleted: Boolean = false
)

解释:

  • id:任务的唯一标识符。
  • name:任务的名称。
  • isCompleted:任务是否完成,默认值为 false
Step 2: 创建 ViewModel

ViewModel 负责持有和管理任务列表数据。我们创建一个 TaskViewModel,它包含 LiveData 来保存任务列表,并提供方法来添加任务。

// TaskViewModel.kt
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelclass TaskViewModel : ViewModel() {// 私有的 MutableLiveData 保存任务列表private val _taskList = MutableLiveData<List<Task>>()val taskList: LiveData<List<Task>> get() = _taskList// 初始化任务列表为空init {_taskList.value = listOf()}// 添加新任务的方法fun addTask(taskName: String) {val currentList = _taskList.value ?: listOf()val newTask = Task(id = currentList.size + 1, name = taskName)_taskList.value = currentList + newTask}
}

解释:

  • MutableLiveData 是一个可变的 LiveData,用于在内部管理数据。
  • LiveData 对外暴露,只读,用于观察任务列表的变化。
  • addTask() 方法会向当前的任务列表中添加新任务,然后更新 LiveData,从而自动通知UI更新。
Step 3: 创建 Adapter

为了在 RecyclerView 中显示任务列表,我们需要创建一个适配器 TaskAdapter 来处理数据绑定。

// TaskAdapter.kt
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.todoapp.databinding.ItemTaskBindingclass TaskAdapter(private var taskList: List<Task>) : RecyclerView.Adapter<TaskAdapter.TaskViewHolder>() {// ViewHolder 用于保存每个任务视图的引用class TaskViewHolder(private val binding: ItemTaskBinding) : RecyclerView.ViewHolder(binding.root) {fun bind(task: Task) {binding.taskName.text = task.namebinding.taskCompleted.text = if (task.isCompleted) "Completed" else "Not Completed"}}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder {val binding = ItemTaskBinding.inflate(LayoutInflater.from(parent.context), parent, false)return TaskViewHolder(binding)}override fun onBindViewHolder(holder: TaskViewHolder, position: Int) {val task = taskList[position]holder.bind(task)}override fun getItemCount() = taskList.size// 更新任务列表的方法fun updateTasks(newTasks: List<Task>) {taskList = newTasksnotifyDataSetChanged()}
}

解释:

  • TaskViewHolderRecyclerView.ViewHolder 的子类,用于保存和绑定任务数据到UI。
  • onCreateViewHolder 创建并初始化视图。
  • onBindViewHolder 绑定每个任务的数据。
  • updateTasks 方法用来更新任务列表并通知 RecyclerView 重新渲染。
Step 4: 创建 Activity

MainActivity 中,我们需要初始化 ViewModelRecyclerView,并且通过观察 LiveData 来实时更新UI。

  1. activity_main.xml

在布局文件中,我们需要一个 RecyclerView 用于展示任务列表,还有一个 EditTextButton 用于添加任务。

<!-- activity_main.xml -->
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><EditTextandroid:id="@+id/etTaskName"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Enter task name" /><Buttonandroid:id="@+id/btnAddTask"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Add Task" /><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp" />
</LinearLayout>
  1. MainActivity.kt

MainActivity 中,我们需要初始化 ViewModel,设置 RecyclerView,并在 LiveData 发生变化时更新UI。

// MainActivity.kt
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.todoapp.databinding.ActivityMainBindingclass MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBindingprivate lateinit var taskAdapter: TaskAdapterprivate val taskViewModel: TaskViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)// 设置 RecyclerViewtaskAdapter = TaskAdapter(listOf())binding.recyclerView.layoutManager = LinearLayoutManager(this)binding.recyclerView.adapter = taskAdapter// 观察任务列表数据变化taskViewModel.taskList.observe(this) { tasks ->taskAdapter.updateTasks(tasks)}// 添加任务按钮点击事件binding.btnAddTask.setOnClickListener {val taskName = binding.etTaskName.text.toString()if (taskName.isNotEmpty()) {taskViewModel.addTask(taskName)binding.etTaskName.text.clear()}}}
}

解释:

  • by viewModels() 是一个 Kotlin 委托,用于初始化 ViewModel
  • observe() 方法用来观察 LiveData,当 taskList 发生变化时,适配器会更新任务列表。
  • btnAddTask.setOnClickListener 中,用户输入任务名并点击“Add Task”按钮后,ViewModel 将新任务添加到任务列表中。

4. 总结

在这个实例中,我们通过构建一个简单的待办事项应用,学习了 ViewModelLiveData 的基础使用。你已经掌握了如何使用 LiveData 来观察数据变化,并通过 ViewModel 来持久化UI数据。这样做不仅能够让应用更具响应性,还能让数据在配置变化时保持不变。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣(leetcode)题目总结——动态规划篇

leetcode 经典题分类 链表数组字符串哈希表二分法双指针滑动窗口递归/回溯动态规划二叉树辅助栈 本系列专栏&#xff1a;点击进入 leetcode题目分类 关注走一波 前言&#xff1a;本系列文章初衷是为了按类别整理出力扣&#xff08;leetcode&#xff09;最经典题目&#xff0c…

MySQL超详细安装配置教程(亲测有效)

目录 1.下载mysql 2.环境配置 3.安装mysql ​4.navicat工具下载与连接 ​5总结 1.下载mysql mysql下载--MySQL &#xff1a;&#xff1a; 下载 MySQL 社区服务器 下载的时候这里直接逃过就行 我这里的版本是最新的mysql8.0.37 下载完成之后,将压缩包进行解压 这里我建议大…

高阶云服务-ELB+AS

ELBAS 弹性负载均衡弹性伸缩 原来1台web服务器不满足相应&#xff0c;现部署多台提供相同服务&#xff1b; 由于多个服务器多个ip该如何提供给应用呢&#xff1f; 引申出负载均衡&#xff08;HAProxy&#xff0c;LVS01四层&#xff0c;Nginx七层&#xff09; 防单点故障做主备…

python蓝桥杯刷题2

1.最短路 题解&#xff1a;这个采用暴力枚举&#xff0c;自己数一下就好了 2.门牌制作 题解&#xff1a;门牌号从1到2020&#xff0c;使用for循环遍历一遍&#xff0c;因为range函数无法调用最后一个数字&#xff0c;所以设置成1到2021即可&#xff0c;然后每一次for循环&…

阿里云轻量应用服务器可以用在哪些场景呢

在数字化转型的浪潮中&#xff0c;中小企业面临着如何快速、高效地上云的挑战。阿里云轻量应用服务器&#xff08;SWAS&#xff09;作为一款专为中小企业设计的云服务产品&#xff0c;提供了简单易用、经济实惠的解决方案&#xff0c;助力企业轻松实现云端部署&#xff0c;赋能…

git合并分支

首先是UI非常建议切换成传统的UI&#xff1a; 当前所在分支email 右键切换的时候chekout 点击之后就可以切换了 再执行查看就知道已经切换到了main分支&#xff1b; 总结&#xff1a; git branch 查看当前分支&#xff0c;其实不用查看你看或者小图标&#xff0c;就是那…

《生成式 AI》课程 第3講 CODE TASK执行文章摘要的机器人

课程 《生成式 AI》课程 第3講&#xff1a;訓練不了人工智慧嗎&#xff1f;你可以訓練你自己-CSDN博客 任务1:总结 1.我们希望你创建一个可以执行文章摘要的机器人。 2.设计一个提示符&#xff0c;使语言模型能够对文章进行总结。 model: gpt-4o-mini,#gpt-3.5-turbo, import…

微众银行申请专利:不过分丢失泛用能力,提高语音大模型对困难样本学习效率

微众银行正申请一项名为“语音大模型训练方法、装置、设备、存储介质以及产品”的发明专利。其申请于2024年8月22日,公布于2024年10月15日,涉及语音识别技术领域。 方法应用于待训练的语音大模型,包括:获取当前批次的训练样本集,其中包括语音标注样本集;将当前批次的训练…

23种设计模式-备忘录(Memento)设计模式

文章目录 一.什么是备忘录设计模式&#xff1f;二.备忘录模式的特点三.备忘录模式的结构四.备忘录模式的优缺点五.备忘录模式的 C 实现六.备忘录模式的 Java 实现七.总结 类图&#xff1a; 备忘录设计模式类图 一.什么是备忘录设计模式&#xff1f; 备忘录设计模式&#xff08…

Docker入门之Windows安装Docker初体验

在之前我们认识了docker的容器&#xff0c;了解了docker的相关概念&#xff1a;镜像&#xff0c;容器&#xff0c;仓库&#xff1a;面试官让你介绍一下docker&#xff0c;别再说不知道了 之后又带大家动手体验了一下docker从零开始玩转 Docker&#xff1a;一站式入门指南&#…

视频直播5G CPE解决方案:ZX7981PG/ZX7981PMWIFI6网络覆盖

方案背景 视频直播蓬勃发展的当下&#xff0c;传统直播网络联网方式的局限性越来越明显。目前传统直播的局限性主要集中在以下几个方面&#xff1a; 传统直播间网络架构条件有限&#xff0c;可连接WIFI数量少&#xff0c;多终端同时直播难以维持&#xff1b;目前4G网络带宽有限…

生数科技发布 Vidu 1.5 新版本,引领视频大模型新潮流

在国内视频大模型领域&#xff0c;生数科技一直以创新和突破而备受瞩目。近日&#xff0c;生数科技再度发力&#xff0c;发布了 Vidu 1.5 新版本&#xff0c;为视频创作带来了全新的变革与机遇。 Vidu 1.5 新版本在多个方面展现出了卓越的性能和创新的特点。首先&#xff0c;它…

unity 打包WebGL打开后Input无法输入中文,在手机端无法调用输入法(使用WebGLInput)

成果展示 1、只是在电脑上运行时 使用TexMeshPro-InputField组件就可以输入中文了 2.不仅在电脑上运行&#xff0c;还需要在移动端运行 这个时候就需要使用WebGLInput插件&#xff0c;连接里有测试demo 1、下载后把WebGLSupport.unitypackage 导入到工程里 2、给input添加两…

MySQL8 安装教程

一、从官网下载mysql-8.0.18-winx64.zip安装文件&#xff08; 从 https://dev.mysql.com/downloads/file/?id484900 下载zip版本安装包 mysql-8.0.18-winx64.zip 解压到本地磁盘中&#xff0c;例如解压到&#xff1a;D盘根目录&#xff0c;并改名为MySQL mysql-8.0.34-winx6…

fastapi 调用ollama之下的sqlcoder模式进行对话操作数据库

from fastapi import FastAPI, HTTPException, Request from pydantic import BaseModel import ollama import mysql.connector from mysql.connector.cursor import MySQLCursor import jsonapp FastAPI()# 数据库连接配置 DB_CONFIG {"database": "web&quo…

自动化报表怎么写

自动化报表设计 标题 日期 筛选器 具体字段自由字段 迷你图 同环比 条件格式 步骤 填充数值 1、先筛选战区日期sumifs(纯数值-注册人数&#xff0c;纯数值-战区列&#xff0c;周报-战区单元格&#xff0c;纯数值-日期&#xff0c;周报-日期单元格) 需要注意⚠️纯数值里的单元格…

学习笔记022——Ubuntu 安装 MySQL8.0版本踩坑记录

目录 1、查看可安装 MySQL 版本 2、Ubuntu安装 MySQL8.0 3、MySQL8.0 区分大小写问题 4、MySQL8.0 设置sql_mode 5、MySQL8.0 改端口33060&#xff08;个人遇到问题&#xff09; 1、查看可安装 MySQL 版本 ## 列出可用的MySQL版本&#xff08;列出所有可用的MySQL版本以…

优化装配,提升品质:虚拟装配在汽车制造中的关键作用

汽车是各种零部件的有机结合体&#xff0c;因此汽车的装配工艺水平和装配质量直接影响着汽车的质量与性能。在汽车装配过程中&#xff0c;经常会发生零部件间干涉或装配顺序不合理等现象&#xff0c;且许多零部件制造阶段产生的质量隐患要等到实际装配阶段才能显现出来&#xf…

Office-Tab-for-Mac Office 窗口标签化,Office 多文件标签化管理

Office Tab&#xff1a;让操作更高效&#xff0c;给微软 Office 添加多标签页功能 Office 可以说是大家装机必备的软件&#xff0c;无论学习还是工作都少不了。其中最强大、用的最多的&#xff0c;还是微软的 Microsoft Office。 遗憾的是&#xff0c;微软的 Office 不支持多…

【网络】Socket编程TCP/UDP序列化和反序列化理解应用层(C++实现)Json::Value

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.基于Socket的UDP和TCP编程介绍 1.1 基本TCP客户—服务器程序设计基本框架 ​编辑1.2 基本UDP客户—服务器程序设计基本框…