ViewModel 原理

# ViewModel 原理

在现代Android应用开发中,ViewModel是架构组件库的一个关键部分,它在提高应用的稳定性和性能方面发挥着重要作用。在这篇文章中,我们将深入探讨ViewModel的工作原理和最佳实践。

ViewModel简介

ViewModel是Android Jetpack架构组件的一部分,它的主要目的是管理和存储与UI相关的数据。ViewModel的设计初衷是使数据能够在配置更改(如屏幕旋转)后继续存在。

工作原理

数据持久性

  • 当设备配置更改导致Activity重建时,ViewModel可以保留数据。它是通过系统保存的实例状态来实现的,从而使数据在Activity重新创建时依然可用。

生命周期意识

  • ViewModel与Activity或Fragment的生命周期紧密相连。它在Activity或Fragment的整个生命周期内都是活跃的,并在它们被完全销毁时清理。

使用ViewModel的优势

  • 数据管理:ViewModel使得管理UI相关的数据更加简单和高效。
  • 减少内存泄漏:由于ViewModel与视图的生命周期是分离的,因此减少了因为持有Activity或Fragment引用而导致的内存泄漏的风险。
  • 更好的数据持久化:ViewModel可以在配置更改时保留重要数据,避免了不必要的数据库或网络请求。

实现ViewModel

创建ViewModel类

  • ViewModel的创建需要继承ViewModel类。
  • 可以在ViewModel内部实现数据的加载和处理逻辑。

与Activity或Fragment关联

  • ViewModel通过ViewModelProvider与Activity或Fragment绑定。
  • 这样可以确保ViewModel的生命周期与Activity或Fragment的生命周期同步。

处理配置更改

  • 在配置更改(如屏幕旋转)时,ViewModel帮助保存重要的UI数据。
  • 当Activity或Fragment重新创建时,可以从ViewModel中恢复数据。

最佳实践

  • 避免在ViewModel中引用视图:ViewModel不应持有对Activity、Fragment或View的引用。
  • 使用LiveData:LiveData可以用来观察数据的变化,并在数据变化时更新UI。
  • 分离关注点:ViewModel应该专注于数据处理,而UI逻辑应该留在Activity或Fragment中。

ViewModel的创建方式

1. 使用ViewModelProvider

这是创建ViewModel的最常见方式。ViewModelProvider会与Activity或Fragment的生命周期关联,确保在配置更改时ViewModel不会被重新创建。

import androidx.lifecycle.ViewModelProvider
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
    }
}

在这个例子中,MyViewModel 是通过ViewModelProvider创建的,并与MainActivity的生命周期关联。

2. 使用ViewModel的工厂方法

当需要向ViewModel传递参数时,可以使用ViewModel的工厂方法来创建ViewModel。

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MyViewModel(val myParam: String) : ViewModel() {
    // ViewModel的逻辑
}

class MyViewModelFactory(private val myParam: String) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
            return MyViewModel(myParam) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val factory = MyViewModelFactory("Hello")
        viewModel = ViewModelProvider(this, factory).get(MyViewModel::class.java)
    }
}

在这个例子中,MyViewModel 需要一个字符串参数。因此,创建了一个MyViewModelFactory
来传递这个参数,并使用这个工厂来创建MyViewModel的实例。


ViewModel 相关面试题及回答

面试题1: ViewModel是什么,它是如何工作的?

  • 回答:
    ViewModel是一个架构组件,它的主要职责是管理界面控制器(如Activity和Fragment)的数据。它帮助保存数据,以便在配置更改(如屏幕旋转)时数据不会丢失。ViewModel的实例与特定的Activity或Fragment的生命周期绑定,但比单个Activity或Fragment的实例生命周期更长,因此能够在界面控制器重建时保持数据状态。

面试题2: 为什么在ViewModel中持有Activity的引用是一个不好的实践?

  • 回答:
    在ViewModel中持有Activity的引用会导致内存泄露,因为ViewModel的生命周期比它所关联的Activity长。如果ViewModel持有Activity的引用,即使Activity需要被销毁以释放资源,由于ViewModel的存在,它无法被垃圾回收器回收,从而导致内存泄漏。

面试题3: LiveData是什么,它如何与ViewModel配合使用?

  • 回答:
    LiveData是一个可观察的数据存储器类,特别是用于保存可观察数据,并且能在数据改变时通知视图。它与ViewModel配合使用,因为LiveData遵循观察者模式,这使得当数据改变时,UI可以立即更新。LiveData也是生命周期感知的,这意味着它只会在Activity或Fragment处于活跃状态时更新UI,从而避免内存泄漏。

面试题4: 如何在ViewModel中处理耗时任务?

  • 回答:
    在ViewModel中处理耗时任务(如网络请求)时,应该使用后台线程来避免阻塞UI线程。可以利用协程或RxJava等异步处理框架来实现。这些任务应该与ViewModel的生命周期关联,以确保在ViewModel被销毁时,相关的异步任务也会相应地被取消或清理,以避免内存泄露。

面试题5: 解释ViewModel的onCleared()方法。

  • 回答: onCleared()
    方法在ViewModel即将被销毁时调用,这通常发生在与其关联的Activity或Fragment被永久销毁时(不是由于配置更改)。这个方法是清理资源的理想位置,比如取消所有进行中的异步任务、移除监听器或者释放对外部资源的引用。

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

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

相关文章

2024.03.03 健身打卡第 14 天

成功只有一个——按照自己的方式&#xff0c;去度过人生 2024.03.03 健身打卡第 14 天

[Vulnhub]靶场 Red

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 …

前端el-date-picker传递的日期格式不是自己想要的格式

解决方法&#xff1a; 添加format和value-format属性进行解决。 format“YYYY-MM-DD” value-format“YYYY-MM-DD” 注意&#xff1a;日期格式要用大写&#xff01;&#xff01;&#xff01;&#xff01;用小写会出现错误&#xff0c;不能回填选择的日期&#xff0c;会直接传入…

TCP/IP-常用网络协议自定义结构体

1、TCP/IP模型&#xff1a; 2、TCP/IP- 各层级网络协议&#xff08;从下往上&#xff09;&#xff1a; 1&#xff09;数据链路层&#xff1a; ARP: 地址解析协议&#xff0c;用IP地址获取MAC地址的协议&#xff0c;通过ip的地址获取mac地 …

带你快速初步了解Python字典

1.字典 定义多个数据一般使用列表&#xff0c;但是列表也存在一定的缺陷 若列表中有多个元素&#xff0c;想访问其中某个元素&#xff0c;比较不方便 定义字典的语法&#xff1a;{key1:value1, key2:value2, key3:value3......} 字典和列表习惯的使用场景&#xff1a; &qu…

PCSA时钟控制集成之时钟门控级别

这一部分描述了&#xff1a; • 时钟门控的级别。 • 实现最大效果的时钟门位置。 • 实现有效和高效时钟门控的集成方法。 时钟树是由时钟缓冲器构建的&#xff0c;这些缓冲器在时钟源&#xff08;时钟输入或PLL&#xff09;与时钟终端&#xff08;寄存器或RAM&#xff09…

软件测试项目实战,某购物车/测试点分析实战(详细步骤)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 第一步&#xff1…

SpringBoot整合OAuth2 实现单点登录 SSO

单点登录&#xff1a; SSO服务端和SSO客户端直接是通过授权以后发放Token的形式来访问受保护的资源相对于浏览器来说&#xff0c;业务系统是服务端&#xff0c;相对于SSO服务端来说&#xff0c;业务系统是客户端浏览器和业务系统之间通过会话正常访问不是每次浏览器请求都要去S…

Pyglet图形界面版2048游戏——详尽实现教程(上)

目录 Pyglet图形界面版2048游戏 一、色块展示 二、绘制标题 三、方阵色块 四、界面布局 五、键鼠操作 Pyglet图形界面版2048游戏 一、色块展示 准备好游戏数字的背景颜色&#xff0c;如以下12种&#xff1a; COLOR ((206, 194, 180, 255), (237, 229, 218, 255), (23…

详解算法的时间复杂度和空间复杂度!

目录 ​编辑 1. 算法效率 2. 时间复杂度 2.1 时间复杂度的概念 2.2 大O的表示渐进法 2.3 一个栗子 3. 空间复杂度 4. 常见复杂度对比 5. 完结散花 ​​​​​​​ 悟已往之不谏&#xff0c;知来者犹可追 创作不易&#xff0c;宝子们&#xff01;如果这篇文章对你们有…

C++之queue和deque

1、queue queue&#xff08;队列&#xff09;&#xff0c;一种数据结构&#xff0c;可以让某些数据结构的操作变得简单。队列&#xff08;queue&#xff09;最大的特点就是先进先出。就是说先放入queue容器的元素一定是要先出队列之后&#xff0c;比它后进入队列的元素才能够出…

二维码门楼牌管理系统技术服务详解:性能标准与反光膜要求

文章目录 前言一、二维码门楼牌管理系统技术服务的性能要求二、反光膜的性能标准三、制作完成的反光膜表层保护 前言 随着科技的快速发展&#xff0c;二维码门楼牌管理系统在现代化城市管理中扮演着越来越重要的角色。这一系统不仅提高了管理效率&#xff0c;还为市民提供了更…

Autosar Appl介绍

AUTOSAR架构中的应用层 AUTOSAR 应用层构成AUTOSAR 架构中的最顶层,被认为对所有车辆应用至关重要。AUTOSAR 标准使用“组件”概念指定应用层实现。 在谈论应用层实现时,应该考虑的三个最重要的部分是: AUTOSAR 应用软件组件这些组件的 AUTOSAR 端口AUTOSAR 端口接口 AUTOS…

steam++加速问题:出现显示443端口被 vmware-hostd(9860)占用的错误。

目录 前言&#xff1a; 正文&#xff1a; 前言&#xff1a; 使用Steam对GitHub进行加速处理时&#xff0c;建议使用2.8.6版本。 下载地址如下&#xff1a;Release 2.8.6 BeyondDimension/SteamTools GitHub 下载时注意自己的系统位数 正文&#xff1a; 使用GitHub时会使…

任务拆解的艺术

1.任务拆解背后的深层逻辑 任务拆解背后的深层逻辑主要涉及以下几个方面&#xff1a; 分解复杂性&#xff1a; 任务拆解的首要目的是分解复杂的大目标或任务&#xff0c;将其分解成更小、更具体的部分。这种分解有助于减少问题的复杂性&#xff0c;使其更易于理解和解决。通过将…

DC-2靶机详解

写写自己打DC-2的过程 使用工具 kali DC-2的靶机下载地址为&#xff1a;https://www.vulnhub.com/entry/dc-2,311/ 环境配置。 Kali和DC-2都设置为NAT模式&#xff0c;都为仅主机模式也可以。 信息收集 arp-scan -l nmap -sn 192.168.236.0/24 获取靶机ip&#xff1a;192.16…

K8S之Deployment的介绍和使用

Deployment的理论和实操 Deployment控制器&#xff1a;概念、原理解读概述工作原理 编写Deployment资源清单文件使用案例&#xff1a;创建一个web站点Deployment管理pod&#xff1a;扩容、缩容通过deployment管理应用&#xff0c;实现扩容&#xff0c;把副本数变成3通过deploym…

C++重新入门-vector容器

目录 1.动态数组&#xff1a; 2.头文件和命名空间&#xff1a; 3.创建和初始化&#xff1a; 使用默认构造函数创建空的std::vector&#xff1a; 使用初始化列表初始化std::vector&#xff1a; 使用拷贝构造函数&#xff1a; 使用范围构造函数&#xff1a; 使用重复值初…

Tkinter.Text控件中,文本存在某个关键字的将被高亮显示(标记颜色+字体加粗)

在Tkinter的Text控件中&#xff0c;要标记某个关键字并改变其颜色&#xff0c;你可以使用tag_add方法来给包含关键字的文本添加标签&#xff0c;然后使用tag_config方法来配置该标签的显示样式&#xff0c;包括前景色&#xff08;字体颜色&#xff09;和背景色等。以下是一个完…

使用腾讯云go sdk 查询对象存储中最新文件

背景&#xff1a; 腾讯云账号下&#xff0c;有很多对象存储COS桶&#xff1a; 我现在想确认某一个对象存储桶的活跃程度&#xff0c;简单的来说。我想知道这个桶里面最后上传的一个文件是什么&#xff0c;以及它的上传时间戳。 本文将介绍如何使用腾讯云对象存储&#xff08;…