【Jetpack】Room + ViewModel + LiveData 综合使用 ( 核心要点说明 )

Jetpack 是一个由 Android 官方推出的一套组件,旨在帮助开发人员更便捷地构建高质量的应用程序。在 Jetpack 中,Room、ViewModel 和 LiveData 都是非常重要的组件,在实际开发中,它们经常被用于构建较复杂的应用。本文将围绕着如何综合使用 Room、ViewModel 和 LiveData 这三个核心组件展开,为大家详细介绍其核心要点和代码示例。

1.核心要点说明

1.1 Room

Room 是针对 SQLite 数据库的一个 ORM(对象关系映射)库,它提供了一种类型安全、方便快捷的方式来访问 SQLite 数据库。使用 Room 可以避免直接操作 SQLiteDatabase 的逻辑,减少程序员的工作量和出错概率。

1.2 ViewModel

ViewModel 是一个设计模式,它可以使得应用程序的 UI 和数据逻辑分离,从而更方便地管理数据。ViewModel 的核心作用就是保存和管理数据,例如将数据从 Model 中提取到 ViewModel 中,也可以在 ViewModel 内进行数据处理,而不必将数据交给 View 层或者 Model 层处理。

1.3 LiveData

LiveData 是一个可以观察数据的组件,它可以保证数据的及时更新,并且这种更新方式是基于数据的生命周期的。LiveData 具备数据驱动、生命周期感知、线程安全等特性,可以更好的协助数据和界面的交互。

2.组合方式

在实际开发中,可以通过将 Room、ViewModel 和 LiveData 组合起来使用,来构建一个更加高效的应用程序。下面是以 Room 为数据源,ViewModel 作为数据管理层,LiveData 作为数据传递媒介的组合方式:

2.1 构建 Room 数据库

首先,需要通过 Room 的注解定义需要保存的数据实体类,并且需要创建一个继承于 RoomDatabase 的抽象基类。

@Entity(tableName = "user")
data class User(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var name: String,
    var age: Int
)

@Dao
interface UserDao {
    @Insert
    suspend fun insertUser(user: User)

    @Update
    suspend fun updateUser(user: User)

    @Query("SELECT * FROM user WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?
}

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao

    companion object {
        private const val DATABASE_NAME = "app_database"

        @Volatile
        private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    DATABASE_NAME
                ).build()
            }
        }
    }
}

2.2 创建 ViewModel

创建一个继承于 AndroidViewModel 的 ViewModel 类,并将数据源指向 Room 数据库,同时在 ViewModel 中使用协程进行数据访问操作,以此来确保异步访问 Room 的线程安全。

class UserViewModel(application: Application): AndroidViewModel(application) {
    private val userDao = AppDatabase.getInstance(application).userDao()

    private val _userByIdLiveData = MutableLiveData<User>()
    val userByIdLiveData: LiveData<User>
        get() = _userByIdLiveData

    fun getUserById(userId: Int) {
        viewModelScope.launch {
            val user = userDao.getUserById(userId)
            user?.let {
                _userByIdLiveData.postValue(user)
            }
        }
    }

    fun insertUser(user: User) {
        viewModelScope.launch {
            userDao.insertUser(user)
        }
    }

    fun updateUser(user: User) {
        viewModelScope.launch {
            userDao.updateUser(user)
        }
    }
}

2.3 使用 LiveData 传递数据

在 Activity 或 Fragment 中,通过获取 ViewModel 实例,可以观察 LiveData 中的数据,并且在数据变化时相应地进行 UI 的更新。

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var userViewModel: UserViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        userViewModel = ViewModelProvider(this).get(UserViewModel::class.java)

        binding.button.setOnClickListener {
            userViewModel.getUserById(1)
        }

        userViewModel.userByIdLiveData.observe(this, Observer<User> {
            binding.textView.text = it?.name
        })
    }
}

3.代码示例

上述示例代码可能还不够直观,下面提供一个完整的代码示例来展示 Room、ViewModel 和 LiveData 的组合用法。

3.1 定义数据实体类

@Entity(tableName = "user")
data class User(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var name: String = "",
    var age: Int = 0
)

3.2 定义 Dao 接口

@Dao
interface UserDao {
    @Insert
    suspend fun insertUser(user: User)

    @Update
    suspend fun updateUser(user: User)

    @Query("SELECT * FROM user WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?
}

3.3 创建 Room 数据库

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao

    companion object {
        private const val DATABASE_NAME = "app_database"

        @Volatile
        private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    DATABASE_NAME
                ).build()
            }
        }
    }
}

3.4 创建 ViewModel

class UserViewModel(application: Application): AndroidViewModel(application) {
    private val userDao = AppDatabase.getInstance(application).userDao()

    private val _userByIdLiveData = MutableLiveData<User>()
    val userByIdLiveData: LiveData<User>
        get() = _userByIdLiveData

    fun getUserById(userId: Int) {
        viewModelScope.launch {
            val user = userDao.getUserById(userId)
            user?.let {
                _userByIdLiveData.postValue(user)
            }
        }
    }

    fun insertUser(user: User) {
        viewModelScope.launch {
            userDao.insertUser(user)
        }
    }

    fun updateUser(user: User) 
        viewModelScope.launch {
            userDao.updateUser(user)
        }
    }
}

3.5 在 Activity 中使用 ViewModel 和 LiveData

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var userViewModel: UserViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        userViewModel = ViewModelProvider(this).get(UserViewModel::class.java)

        binding.button.setOnClickListener {
            userViewModel.getUserById(1)
        }

        userViewModel.userByIdLiveData.observe(this, Observer<User> {
            binding.textView.text = it?.name
        })
    }
}

在这个示例中,我们已经成功地将 Room、ViewModel 和 LiveData 组合起来使用,从而构建了一个高效的应用程序。我们可以通过定义数据实体类、创建 Room 数据库、创建 ViewModel 以及在 Activity(或 Fragment)中使用 ViewModel 和 LiveData 来实现这一目标。

4.总结

Room、ViewModel 和 LiveData 是 Android Jetpack 最常用的三个组件之一,它们的功能和作用都非常明确,可以分别负责数据存储、数据管理以及数据传递等方面的工作。在实际开发中,我们可以结合使用这三个组件来构建一个高效的应用程序,并且可以通过协程等方式来确保 Room 数据库的线程安全和异步访问。

总的来说,Room、ViewModel 和 LiveData 的组合使用可以极大地提升应用程序的性能和可维护性,同时也可以帮助开发者更好地理解和掌握 Android Jetpack 的相关知识。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

facebook文本生成音乐项目-audiocraft 安装教程

文章目录 所需环境安装ffmpeg克隆项目仓库安装相关依赖库运行项目模型下载自动下载模型失败MusicGen 模型下载地址 所需环境 ffmpegpython>3.9gitcuda118&#xff08;torch>2.0&#xff09; 安装ffmpeg 下载地址 下载后解压&#xff0c;然后将解压后的目录配置到系统…

电影《天空之城》观后感

上周看了电影《天空之城》这部电影&#xff0c;这部电影是六一儿童节时上映的&#xff0c;本周也算是补票吧&#xff0c;童年时&#xff0c;看的都是免费的&#xff0c;早已经忘记是在哪里看到的&#xff0c;但当时对自己触动很大&#xff0c;算是启蒙电影&#xff0c;所以今天…

Tinker 组件修复,踩坑

1、You need to use a Theme.AppCompat theme (or descendant) with this activity. 复现步骤 补丁加载成功之后重启应用&#xff0c;再退出应用重进闪退 日志 TinkerUncaughtHandler catch exception:java.lang.IllegalStateException: You need to use a Theme.AppCompat th…

网络传输中的那些编码之-UTF8编码漫谈

编码为什么是一个重要的话题&#xff0c;因为我们和计算机交互的主要方式目前还是文字字符。作为一个程序员&#xff0c;相信大部分都都被字符和编码的问题折磨过&#xff0c;从键盘输入文字字符到编辑器 中&#xff0c;编辑器存储字符到硬盘&#xff0c;再到具体一个编程语言如…

Java 八股文-基础篇

Java 基础 一、Java 概述 1.什么是 Java&#xff1f; Java 是一门面向对象的编程语言&#xff0c;不仅吸收了 C语言的各种优点&#xff0c;还摒弃了 C里难以理解的多继承、指针等概念&#xff0c;因此 Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编…

NB-lot和LoRa真正的差别在哪里?

就像要把大象装冰箱一样&#xff0c;物联网&#xff0c;万物互联也是要分步骤的。 一、感知层(信息获取层)&#xff0c;即利用各种传感器等设备随时随地获取物体的信息; 二、网络层(信息传输层)&#xff0c;通过各种电信网络与互联网的融合&#xff0c;将物体的信息实时准确地…

Mybatis学习之插件

Mybatis学习之插件 Plugins Mybatis中的插件虽然名称叫插件&#xff0c;但实质上是通过动态代理实现的。和我们平时讲的插件概念不一样&#xff0c;但是本质上都是给外部提供接口进行扩展。 MyBatis 允许我们在映射语句执行过程中的某一点进行拦截调用。MyBatis允许我们使用…

浪潮 KaiwuDB x 大数据中心 | 数据驱动政府治理能力快速提升

业务背景 我国工业互联网大数据资源存在孤立、分散、封闭等问题&#xff0c;数据价值未能得到有效利用&#xff0c;数据主权和数据安全面临重大威胁。 发挥数据对工业经济的基础支撑和创新引擎作用&#xff0c;可促进工业互联网的创新发展&#xff0c;加速数据驱动政府治理能…

CVPR23 | 可编辑3D场景布局的文本引导多对象合成NeRF

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2303.13843 0.背景&#xff1a; 最近&#xff0c;文本到图像生成通过将视觉-语言预训练模型与扩散模型相结合&#xff0c;取得了巨大的成功。这些突破也使得强大…

cortex A7核按键中断实验

cortex A7核按键中断实验 一、分析电路图 实验目的&#xff1a;完成板子三个按键操作 1.1 电路图IO口 KEY1------>PF9 KEY2------>PF7 KEY3------>PF8 1.2 工作原理 KEY1 ------> PF9 ------> 按键触发方式&#xff1a;下降沿触发 KEY2 ------> PF7 …

HarmonyOS元服务端云一体化开发快速入门(上)

一、前提条件 您已使用已实名认证的华为开发者帐号登录DevEco Studio。 请确保您的华为开发者帐号余额充足&#xff0c;账户欠费将导致云存储服务开通失败。 二、选择云开发模板 1.选择以下任一种方式&#xff0c;打开工程创建向导界面。 如果当前未打开任何工程&#xff0c…

Question Log

Question Log 提示&#xff1a;记录一下平常遇到的坑 Question Log&#xff08;★ &#xff1e; &#xff09; Question LogⅠ、★ &#xff1e; 使用VsCode构建Unity开发环境1.环境配置2.遇到的相关问题★.The .NET Core SDK cannot be located: A valid dotnet installation …

JS + 浮动 + 递归实现图片瀑布流懒加载

思路 页面 pege 分成左浮动的数列 lineBox&#xff0c;每列中图片 sinImg 依次向下摆放每加载一张图片时&#xff0c;判断页面中哪列的高度最小&#xff0c;将当前图片放到最小的那列尾部监听当前图片 onload 事件&#xff0c;当前图片加载完成后&#xff0c;再加载下一张图片…

力扣题库刷题笔记5--最长回文子串

1、题目如下&#xff1a; 2、个人Python代码实现&#xff1a; 首先想到的是通过类似冒泡排序的方式进行切片&#xff0c;然后判断切片的子字符串是否为回文字符串&#xff0c;然后记录出最长的回文字符串&#xff0c;代码如下&#xff1a; 可以看到&#xff0c;通过切片的方式&…

剑指offer35 复杂链表的复制

复杂链表的复制 文章目录 复杂链表的复制方法一 回溯哈希表第二种解释 方法二&#xff1a;拼接拆分算法流程 参考文献 本题要求我们对一个复杂链表进行复制。在复杂链表中&#xff0c;每个节点除了有一个next指针指向下一个节点&#xff0c;还有一个random指针指向链表中的任意…

嵌入式容器源码解析

问题分析 不同于使用springmvc,在我们使用springboot时无需配置tomcat就可以直接使用&#xff0c;这就说明springboot已经在我们启动项目时将tomcat配置好了&#xff0c;接下来我们就来看看springboot底层是怎么实现的。 源码解析 ServletWebServerFactoryAutoConfiguratio…

Python 标准库 - 并发执行

Python 标准库 - 并发执行 1. 简单介绍2. 程序示例2.1 threading 编程示例2.2 multiprocessing 编程示例2.3 concurrent.futures 编程示例 1. 简单介绍 Python 标准库 非常庞大&#xff0c;所提供的组件涉及范围十分广泛&#xff0c;官方参考链接https://docs.python.org/zh-cn…

unity 3d实现下雨、雾气、萤火虫和火花四溅的粒子效果

文章目录 先看最终效果1. 下雨效果2. 雾气效果3. 萤火虫和火花四溅的效果 3d下雨粒子效果涟漪效果雨滴和涟漪效果结合水花效果雨滴涟漪水花结合问题雾气效果萤火虫火花效果萤火虫和火花效果结合完毕 先看最终效果 1. 下雨效果 2. 雾气效果 3. 萤火虫和火花四溅的效果 3d下雨粒…

函数栈帧的创建与销毁

函数栈帧的创建与销毁 前言认识相关寄存器认识相关汇编命令详解思路图 前言 函数栈帧的创建与销毁在不同编译器下&#xff0c;函数调用过程中栈帧的创建略有差异&#xff0c;具体细节取决于编译器的实现&#xff0c;但大体逻辑是一致的。&#xff08;在使用编译器时&#xff0…

某游戏登录密码加密,webpack

注意&#xff1a;文章内容仅用于学习和技术交流&#xff0c;切勿做出违法的事情&#xff0c;如有侵权请联系我删除。 网址&#xff08;今天的大冤种&#xff09;&#xff1a;aHR0cHM6Ly93d3cuZ205OS5jb20v 一&#xff0c;分析 从上面图片可以看到&#xff0c;他的密码是加密了…