【Android】程序开发组件—探究Jetpack
引言
Jetpack是一个开发组件工具集,它的主要目的是帮助我们编写出更加简洁的代码,并简化我们的开发过程,在这么多的组件当中,最需要我们关注的其实还是架构组件,接下来就对Jetpack的主要架构组件进行学习!
ViewModel
ViewModel的诞生
- 瞬时数据的丢失:在之前应该已经写过一些程序了,当我们开启屏幕旋转的时候会发现之间的数据丢失,这是因为在屏幕旋转的时候相当于新创建了一个当前活动
- 异步调用时的内存泄漏:UI 控制器(Activity 或 Fragment)有自己的生命周期,它们可能会在不需要时被销毁(例如,用户按下 Home 键,或者屏幕旋转)。然而,异步任务一旦开始,通常会在后台线程中运行,直到任务完成,不管 UI 控制器的状态如何,如果在异步任务中持有 UI 控制器的强引用(如直接引用 Activity),那么即使 UI 控制器已经被销毁,这个引用仍然存在。这意味着垃圾回收器(GC)不能回收 UI 控制器的实例,因为它仍然被异步任务引用,从而导致内存泄漏
- 类膨胀提高维护难度和测试难度:类似于活动当中的代码量过多
ViewModel的作用
它是介于View(视图)和Model(数据模型)之间的桥梁,使数据和视图能够分离,也能保持通信

实践:
新建一个活动放置一个TextView,和一个按钮,当每次按下这个按钮就会使TextView部分的数字加一,这个逻辑大家想必都能很快的写出来,找到按钮与文本控件,为按钮注册点击事件,每次使用getText()与setText()方法修改文本部分的内容,但当我们的屏幕进行旋转的时候,数据就会丢失变为0,因此使用ViewModel来解决这个问题,我们为按钮注册点击事件,创建一个MyViewModel继承于ViewModel,将文本内容的数字设置在这里
public class MyViewModel extends ViewModel {public int number;
}
主活动的代码:
public class MainActivity extends AppCompatActivity {private TextView textView;private MyViewModel viewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {......textView = findViewById(R.id.Textview);viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);textView.setText(String.valueOf(viewModel.number));}//为按钮注册的点击事件public void plus(View view) {textView.setText(String.valueOf(++viewModel.number));}
}
大部分的代码之间经常看到,分析一下中间的代码:
ViewModelProvider是Android架构组件库中的一个类,用于获取ViewModel实例。this参数传递的是当前的Activity实例。new ViewModelProvider.AndroidViewModelFactory(getApplication())创建了一个AndroidViewModelFactory实例,它是一个工厂类,用于创建AndroidViewModel类型的ViewModel实例。getApplication()方法用于获取当前应用程序的上下文。.get(MyViewModel.class)调用ViewModelProvider的get方法,传入MyViewModel.class作为参数,以获取MyViewModel的实例。
此时无论我们如何旋转屏幕数据都不会丢失!
ViewModel的生命周期
ViewModel 的生命周期比 Activity 或 Fragment 的生命周期更长,它不会因为配置更改(如屏幕旋转)而重建。
ViewModel 的生命周期
- 创建 (
onCreate): 当ViewModel首次被请求时,它会被创建。这通常发生在Activity或Fragment的onCreate或onCreateView方法中,通过ViewModelProvider获取ViewModel实例时。 - 准备 (
onCleared):ViewModel提供了一个onCleared()方法,这是一个生命周期回调,当ViewModel被清除并且即将销毁时会被调用。你可以在这个回调中执行清理工作,比如取消网络请求、注销观察者等。 - 活跃: 在
ViewModel被创建后,它会保持活跃状态,直到与它关联的Activity或Fragment被销毁。即使Activity因为配置更改(如屏幕旋转)而重建,ViewModel也不会被销毁,它会保持原有的状态。 - 销毁 (
onCleared): 当Activity或Fragment被销毁,并且没有任何其他组件与ViewModel关联时,ViewModel会被销毁。onCleared()方法会在销毁时被调用。
ViewModel 与 Activity/Fragment 生命周期的关系
- Activity/Fragment 创建: 当
Activity或Fragment创建时,你可以通过ViewModelProvider获取ViewModel实例。如果ViewModel已经存在(比如在屏幕旋转后重建Activity时),则直接使用现有的实例。 - Activity/Fragment 重建: 如果
Activity因为配置更改而重建,ViewModel会保持不变,这意味着ViewModel中的数据不会丢失。 - Activity/Fragment 销毁: 当
Activity或Fragment被销毁时,ViewModel不会被销毁,除非没有任何Activity或Fragment与它关联。 - ViewModel 销毁: 当最后一个与
ViewModel相关联的Activity或Fragment被销毁,并且ViewModel没有被其他组件引用时,它会被销毁。
LiveData
和ViewModel之间的关系
当ViewModel中的数据发生变化的时候,LiveData告诉View

使用
简单应用
在活动当中设置一个TextView来显示数据,同样的我们创建一个MyViewModel来防止数据的丢失
public class MyViewModel extends ViewModel {private MutableLiveData<Integer> current;public MutableLiveData<Integer> getCurrent() {if (current == null) {current = new MutableLiveData<>();current.setValue(0);}return current;}
}
public class MainActivity extends AppCompatActivity {TextView textView;MyViewModel viewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {......textView = findViewById(R.id.text);viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);textView.setText(String.valueOf(viewModel.getCurrent().getValue()));viewModel.getCurrent().observe(this, new Observer<Integer>() {@Overridepublic void onChanged(Integer i) {textView.setText(String.valueOf(i));}});startTimer();}private void startTimer() {new Timer().schedule(new TimerTask() {@Overridepublic void run() {//非UI线程postValue()//UI线程setValue()viewModel.getCurrent().postValue(viewModel.getCurrent().getValue() + 1);}}, 1000, 1000);}
}
此时运行程序,屏幕上的数字就在隔一秒加一。
ViewModel与LiveData实现Fragment之间的数据传递
我们创建一个活动,在这个活动当中放置两个碎片,碎片当中放置各自放置一个滑动条,此时活动的布局如下:
当我们拖动碎片当中的一条滑动条,另一个是不动的,因为我们没有将两个碎片联系起来,若我们想将两个滑动条进行关联,使滑动一条滑动条另一个也跟着动就会想到通过Fragment之间的数据传递部分进行联系,就会使主活动的代码量非常大并且 Fragment 之间高度耦合,这使得代码难以维护和扩展。此时我们就可以使用 ViewModel + LiveData去实现。
- 新建一个
MyViewModel继承于ViewModel
public class MyViewModel extends ViewModel {private MutableLiveData<Integer> progress;public MutableLiveData<Integer> getProgress() {if (progress == null) {progress.setValue(0);}return progress;}
}
- 对Fragment部分代码进行修改,另一个碎片的代码也是一样的
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View root = inflater.inflate(R.layout.fragment_blank, container, false);SeekBar seekBar = root.findViewById(R.id.progress_bar1);MyViewModel myViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.AndroidViewModelFactory(getActivity().getApplication())).get(MyViewModel.class);//第一处myViewModel.getProgress().observe(getActivity(), new Observer<Integer>() {@Overridepublic void onChanged(Integer i) {seekBar.setProgress(i);}});//第二处seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {//第三处@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {myViewModel.getProgress().setValue(progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//当用户开始触摸 SeekBar 时,这个方法会被调用}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {//当用户停止触摸 SeekBar 时,这个方法会被调用}});return root;
}
- 第一处:这行代码注册了一个观察者(Observer)来监听
myViewModel.getProgress()LiveData 中的数据变化。当 LiveData 中的值发生变化时,onChanged(Integer i)方法会被调用,并且新的进度值i会被传递到这个方法中。 - 第二处:为 SeekBar 设置了一个监听器,用于监听用户与 SeekBar 的交互(如拖动进度条),当进度条发生变化的时候就会执行里面的方法
- 第三处:当用户拖动 SeekBar 或 SeekBar 的进度发生变化时,这个方法会被调用,
progress参数表示 SeekBar 当前的进度值。fromUser参数是一个布尔值,表示进度变化是否由用户操作引起(如果是程序调用setProgress则为 false)。
我们并没有对主活动进行任何的代码添加与修改,接下来运行程序,当我们无论滑动哪一个碎片里的进度条,另一个也会跟着滑动。
LiveData的优势
- 生命周期感知:
LiveData遵循观察者的生命周期。它确保在观察者(如Activity或Fragment)处于活跃状态时才发送数据更新,从而避免在组件已经销毁后更新 UI 导致的内存泄漏。 - 避免内存泄漏: 由于
LiveData与观察者的生命周期绑定,它不会向已经销毁的观察者发送更新,这减少了因 UI 控制器生命周期管理不当而导致的内存泄漏风险。 - 数据变化的响应式更新: 当数据发生变化时,
LiveData会自动通知活跃的观察者。这种响应式编程模式使得 UI 能够自动响应数据的变化,而无需手动轮询数据。 - 可观察的数据存储:
LiveData可以存储数据的最新状态,当观察者开始观察LiveData时,它会立即接收到当前的数据状态,确保 UI 显示的数据是最新的。 - 支持转换操作:
LiveData可以与Transformations和MediatorLiveData等工具结合使用,支持复杂的数据转换和组合操作,使得数据的处理更加灵活和强大。 - 线程安全:
LiveData的更新操作是线程安全的,你可以在后台线程中更新LiveData的数据,而无需担心线程同步问题。 - 简化数据共享:
LiveData可以简化不同组件间的数据共享,特别是当多个组件需要观察同一份数据时,LiveData提供了一种简洁的观察和更新机制。 - 易于测试: 由于
LiveData的数据更新是可观察的,你可以更容易地编写测试用例来验证数据更新是否按预期触发了 UI 的变化。 - 减少 boilerplate 代码:
LiveData减少了在 Activity 或 Fragment 中处理数据更新和 UI 响应的样板代码,使得代码更加简洁和易于维护。 - 支持数据恢复: 在配置更改(如屏幕旋转)后,
LiveData可以帮助恢复数据状态,因为它保持了数据的最新值,直到观察者重新观察它。
DataBinding
意义:让布局文件承担了部分原本属于页面的工作,使页面与布局耦合度进一步降低
应用
基本应用
根据一个例子来理解吧!
- 新建一个活动,活动当中放置一个图片和两个
TextView控件,我们之前为TextView设置内容都是在主活动当中先获取到控件,在使用setText()方法设置,现在我们试试不在活动当中,此时的布局文件大家都会写,在这里就不展示了 - 打开build.gradle文件,添加以下内容,注意不要忘记
sync now

- 鼠标位于布局文件的最前端点击alt+回车,就会出现以下内容,我们需要添加红色边框部分内容

<data>:这个元素定义了布局文件中可以使用的数据源。<variable:这个元素定义了一个变量,它可以在布局文件中被引用。name="idol":这是变量的名称,在布局文件中可以通过这个名称来引用变量。type="com.example.databinding.Idol":这是变量的类型,它指定了变量的数据类型。在这个例子中,Idol是一个Java类,它可能定义了一些属性,名字、等级,这些属性可以在布局文件中被绑定到UI组件上。
- 对主活动进行修改
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Idol idol = new Idol("熊大", "五星");
activityMainBinding.setIdol(idol);
activityMainBinding:这是一个变量,它存储了绑定类的实例,可以通过这个变量访问布局文件中定义的视图和变量。DataBindingUtil.setContentView:这是一个静态方法,用于将布局文件绑定到当前的Activity。它返回一个绑定类(在这个例子中是ActivityMainBinding)的实例,这个绑定类是由Data Binding库根据布局文件自动生成的。setIdol:这是在ActivityMainBinding类中定义的一个方法,它用于将Idol对象绑定到布局文件中定义的变量idol上。
- 对布局文件进行修改

接下来运行程序:

Important标签和事件绑定
- Important标签
若在我们创建的时候有一个值为整型怎么办,例如在Idol当中将star设置为整型,此时我们就需要将整形转化为字符串类型,创建一个类
public class StarUtils {public static String getStar(int star) {switch (star) {case 1:return "一星";case 2:return "二星";case 3:return "三星";case 4:return "四星";}return "";}
}
修改xml文件
<data><variablename="idol"type="com.example.databinding.Idol" /><import type="com.example.databinding.StarUtils"/>
</data>
<TextViewandroid:id="@+id/dengji"android:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{StarUtils.getStar(idol.star)}"android:textSize="25sp" />
此时在创建对象的时候:
Idol idol = new Idol("熊大", 1);
运行程序,也会得到相应的结果。
<import>:这是Data Binding布局文件中的一个XML标签,用于导入Java类。type:这是<import>标签的一个属性,用于指定要导入的类或包的全限定名。
- 与事件绑定
设置一个按钮,为点击按钮注册事件
public class EventHander {private Context context;public EventHander(Context context) {this.context = context;}public void buttonOnclick(View view) {Toast.makeText(context, "喜欢", Toast.LENGTH_SHORT).show();}
}
将这个类添加到绑定资源当中
<data><variablename="idol"type="com.example.databinding.Idol" /><variablename="eventbutton"type="com.example.databinding.EventHander" /><import type="com.example.databinding.StarUtils"/>
</data>
按钮控件进行添加绑定
android:onClick="@{eventbutton.buttonOnclick}"
此时运行程序,当按下按钮

二级页面的绑定
标签引用二级页面

我们将上面布局的按钮进行删除,将两个TextView控件放在一个xml文件之下,使主活动的xml文件引用这个xml文件,此时我们就不需要在一级页面将star进行转换,将Import标签进行删除,并对引用布局部分进行标签传递修改
<include layout="@layout/sub"app:idol="@{idol}"/>
在二级页面当中TextView的代码与之前的一级页面一样,注意不要忘记添加资源部分。此时运行程序的结果与之前一样。
文章到这里就结束了!
相关文章:
【Android】程序开发组件—探究Jetpack
引言 Jetpack是一个开发组件工具集,它的主要目的是帮助我们编写出更加简洁的代码,并简化我们的开发过程,在这么多的组件当中,最需要我们关注的其实还是架构组件,接下来就对Jetpack的主要架构组件进行学习!…...
pytorch torch.norm函数介绍
torch.norm 函数用于计算张量的范数(norm),可以理解为张量的“长度”或“大小”。根据范数的不同类型,它可以衡量不同的张量性质。该函数可以计算 向量 和 矩阵 的多种范数,如 L1范数、L2范数、无穷范数 等。 1. 函数…...
【lc_hot100】刷题心得
链表 二叉树 二叉树相关的题目基本都有个基本的框架,基本框架就是二叉树的四种遍历方法:前序遍历、中序遍历、后序遍历、层序遍历 往往常用的是前序遍历和中序遍历 图 图跟二叉树一样都有自己的的基本框架,基本框架就是图的两种遍历方法&am…...
FANUC 数控 A06B-6058-H227 伺服放大器
发那科伺服放大器是一种控制电机的电子装置,属于电机控制系统的一部分,用于将输入信号放大并转换成电动机可以理解的信号,从而实现运动控制和定位。 发那科伺服放大器的主要作用包括: 实现运动控制:通过控制…...
Python将表格文件中某些列的数据整体向上移动一行
本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,对其中的每一个文件加以操作——将其中指定的若干列的数据部分都向上移动一行,并将所有操作完毕的Excel表格文件中的数据加以合并,生成一个新的Excel文件的方法。 首…...
基于YOLOv8的PCB缺陷检测算法,加入一种基于内容引导注意力(CGA)的混合融合方案(一)
💡💡💡本文内容:针对基于YOLOv8的PCB缺陷检测算法进行性能提升,加入各个创新点做验证性试验。 1)提出了一种基于内容引导注意力(CGA)的混合融合方案,mAP0.5由原始的0.966提升至0.975 1.PCB缺陷…...
如何在红米手机中恢复已删除的照片?(6 种方式可供选择)
凭借出色的相机和实惠的价格,小米红米系列已成为全球知名品牌。但是,最近有些人抱怨他们在 红米设备上丢失了许多珍贵的图片或视频,并希望弄清楚如何从小米手机恢复已删除的照片。好吧,在小米设备上恢复已删除的视频/照片并不难。…...
嵌入式实时操作系统(RTOS):原理、应用与发展
摘要:本文围绕嵌入式实时操作系统(RTOS)展开。首先介绍嵌入式系统与实时操作系统的概念,阐述嵌入式 RTOS 的体系结构。接着分析其关键特性,包含任务管理(如任务的创建与删除、调度、同步与通信)…...
C#里使用位图容器BitArray
由于经常需要操作一些位表示的数据结构,那么就需要采用位图的管理方式。 在C#里就是使用BitArray来管理位图数据结构,这样就比较方便处理。 这个类可以有多种构造函数,可以满足绝大部分的要求。 比如从网络协议里传送过来的字节流,就可以直接写入到里面,就可以直接获取…...
如何在 Kali Linux 上安装 pip3
如何在 Kali Linux 上安装 pip3 在 Kali Linux 上安装 pip3 的过程非常简单。按照以下步骤,你可以轻松完成安装并开始使用 pip3 管理 Python 软件包。 步骤 1:打开终端 首先,打开你的 Kali Linux 终端。 步骤 2:更新软件包列表…...
5.2 排列与代数余子式
一、求行列式的方法 计算机是利用主元计算行列式的。本节介绍其它两种计算行列式的方法。一是 “大公式”(big formula),它使用了全部 n ! n! n! 个排列计算;二是 “代数余子式公式”(cofactor formula)&…...
java框架第五课(终极版本)SpringBoot
一.关于SpringBoot (1)回忆Spring 传统的Spring由Spring 框架(ioc,aop)加mybatis加Springweb组成,虽然相比原生的java程序Spring框架帮我们大大减少了代码量,减少了冗余,提高了开发效率但是由于Spring框架下的配置和相关的jar包依赖过多&am…...
聚类案例——汽车是否值得购买
对汽车是否值得购买,进行聚类分析: 1、数据指标解释: buying, 购买费用 maint, 维修费用 doors, 车门数量 person, 乘坐人数 lug_boot, 行李箱容量 safety, 安全性 2、对数据进行转换 将字符串转换映射量化为数字 数据加载:…...
网络编程9.10
使用数据库完成工人管理系统: ubuntuubuntu:DB$ ubuntuubuntu:DB$ cat 2.c #include <myhead.h> #include <sqlite3.h> #include <string.h>typedef struct {int id;char name[20];double salary; } Worker;int do_insert(sqlite3 *ppDb) {Worker work;pri…...
如何在SQL Server中恢复多个数据库?
一次性恢复多个 SQL数据库吗可以吗? "是的,可以一次性恢复多个 SQL 数据库。通常情况下,只要备份文件的名称与相应的数据库匹配,且没有附加的日期或时间信息,就可以通过有效的 T-SQL 脚本来完成恢复。如果你希望…...
炸裂!新版 SD WebUI Forge 出图速度更快!支持最新Flux 模型!(保姆级安装教程)
大家是不是经常为SD WebUI卡顿、爆显存而苦恼?一启动SD 电脑就开始发烫, 尤其低显存用户屡屡"中招",不得不一遍遍重启。作为AI绘画的必备工具,WebUI却还有这么多"坑",着实让人不爽!😠 好消息是,…...
laserOdometry.cpp源码注释
本博客用于a-loam源码学习,用于和slam初学者一起学习。 #include <cmath>#include <nav_msgs/Odometry.h>#include <nav_msgs/Path.h> //这两行代码是C中包含头文件的指令,它们用于在ROS(Robot Operating System…...
STM32时钟配置图详解
一图概述: 左侧输入时钟源 Input Frequency (LSE/LSI/HSI/HSE) LSE (Low-Speed External):外部32.768 kHz晶体振荡器,通常用于RTC(实时时钟)。LSI (Low-Speed Internal):内部低速时钟,频率为…...
Vscode——调试时,修改变量值
第一步:点击变量,鼠标右键 第二步:点击 设置值...
1. 初识LLM API:环境配置与多轮对话演示
其实AI应用并不是一个什么很高大上的东西,你可以将它当作一个文字的“调库”行为,“调库”只需要知道库名就行了,这里实际也是如此。甚至你只需要知道你想问什么,将你的消息作为输入,就能从大模型得到输出。而这个“库…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
