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

news/2024/11/19 15:13:09/

在第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、任务名称和任务是否已完成的状态。

kotlin">// 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 来保存任务列表,并提供方法来添加任务。

kotlin">// 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 来处理数据绑定。

kotlin">// 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。

kotlin">// 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.ppmy.cn/news/1548262.html

相关文章

基于Java的药店管理系统

药店管理系统 一&#xff1a;基本介绍开发环境管理员功能模块图系统功能部分数据库表设计 二&#xff1a;部分系统页面展示登录界面管理员管理进货信息界面管理员管理药品信息界面管理员管理员工界面管理员管理供应商信息界面管理员管理销售信息界面员工对信息进行管理员工对销…

在Keil中使用ST-LINK烧录STM32程序指南

文章目录 前言前期准备线路连接下载ST-LINK驱动程序1.通过官网下载2.通过百度网盘下载 安装ST-LINK驱动程序查看电脑是否连接ST-LINKKeil配置ST-LINK编译烧录程序后记 前言 之前玩STM32都是用J-LINK烧录程序&#xff0c;不仅便捷&#xff0c;而且烧录的速度比用串口快好多。 …

5G CPE:为什么活动会场与商铺的网络成为最新选择

在快节奏的现代社会中&#xff0c;无论是举办一场盛大的活动还是经营一家繁忙的商铺&#xff0c;稳定的网络连接都是不可或缺的基石。然而&#xff0c;面对复杂的布线难题或高昂的商业宽带费用&#xff0c;许多场所往往陷入两难境地。幸运的是&#xff0c;5G CPE&#xff08;Cu…

PostgreSQL物化视图详解

物化视图简介 物化视图的产生背景与概念 产生背景 随着数据库规模的增大和查询复杂性的提高&#xff0c;数据库查询的性能问题变得越来越突出。为了优化查询性能&#xff0c;数据库系统引入了物化视图&#xff08;Materialized View&#xff09;的概念。物化视图是一种预先计…

ubuntu24.04设置开机自启动Eureka

ubuntu24.04设置开机自启动Eureka 之前我们是在/root/.bashrc的文件中增加了一条命令 nohup java -jar /usr/software/eurekaServer-auth-prd-03.jar > /usr/software/log.log 2>&1 &但上面这条命令只有在登录root的用户时&#xff0c;才会执行&#xff0c;如果…

React Native 全栈开发实战班 - 性能与调试之打包与发布

在完成 React Native 应用的开发与性能优化后&#xff0c;下一步就是将应用打包并发布到各大应用市场&#xff0c;如 Apple App Store 和 Google Play Store。本章节将详细介绍 React Native 应用的打包与发布流程&#xff0c;包括 Android 和 iOS 平台的打包步骤、签名配置、发…

NLP论文速读(多伦多大学)|利用人类偏好校准来调整机器翻译的元指标

论文速读|MetaMetrics-MT: Tuning Meta-Metrics for Machine Translation via Human Preference Calibration 论文信息&#xff1a; 简介&#xff1a; 本文的背景是机器翻译&#xff08;MT&#xff09;任务的评估。在机器翻译领域&#xff0c;由于不同场景和语言对的需求差异&a…

运维面试题.云计算面试题集锦第一套

运维+网络安全学科基础升就业 测试题(总分100分) 一,单词翻译(10分,直接写在答题卡上) 二,单选题(每题2分,共30题): 1.如下哪个属于管道符?( ) A、|| B、<< C、// D、| 2.有一备份程序mybackup,需要在周一至周五下午1点和晚上8点各运行一次,下面哪条cront…