Jetpack业务架构—四件套(Lifecycle、ViewModel、LiveData、DataBinding)

Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法、减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者可将精力集中于真正重要的编码工作。

Android Jetpack组件的优势:

Jetpack推出的主要目的是为了能够让开发者更加快速、方便以及高质量的完成产品开发

  • 轻松管理应用程序的生命周期,后台任务的管理,导航的处理等
  • 利用Jetpack组件进行开发可以有效减少内存溢出、崩溃的概率,提升应用开发的质量

Jetpack中包含的库包括:

  1. ViewModel:帮助管理UI组件的生命周期并存储和管理UI相关的数据。
  2. LiveData:提供了响应式编程的功能,可以让数据在数据源发生变化时自动更新UI。
  3. Room:提供了一个抽象层,可以让开发者方便地访问和管理SQLite数据库。
  4. Navigation:提供了一种简单、一致的方式来处理应用程序的导航。
  5. WorkManager:提供了一种简单、可靠的方式来管理后台任务。 除此之外,Jetpack还包括了诸如Paging、Data Binding、Preferences、Security等库,这些库都旨在简化开发过程并提高应用程序的性能和可靠性。

Jetpack四件套介绍

Lifecycle

Life生命,cycle周期,顾名思义:Lifecycle是生命周期的意思。它是Jetpack中的一个 生命周期感知型组件 ,可执行操作来感知响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。

使用LifeCycle有什么好处?

LifeCycle可以帮助开发者创建可感知生命周期的组件。这样,组件便能够在其内部管理自己的生命周期,从而降低模块间的耦合度,并降低内存泄漏发生的可能性

举个例子,我们经常需要在页面的onCreate()方法中对组件进行初始化,在onPause()方法中停止组件,而在页面的onDestroy()方法中对组件进行资源回收工作。这样的工作非常烦琐,会让页面与组件之间的耦合度变高。但这些工作又不得不做,因为这可能会引发内存泄漏。

正确使用LifeCycle

使用思路:

  1. 构建一个 Lifecycle 对象(通过一个实现了 LifecycleOwner 接口的对象的 getLifecycle()方法返回),这个对象就是一个被观察者,具有生命周期感知能力
  2. 构建一个 LifecycleObserver 对象,它对指定的 Lifecycle 对象进行监听
  3. 通过将 Lifecycle 对象的 addObserver(…) 方法,将 Lifecycle 对象和 LifecycleObserver 对象进行绑定

①导入依赖(这里直接去官网看最新的版本导入就可以了) 这里给出一些,按需选择,并不是全部都需要的

    dependencies {def lifecycle_version = "2.2.0"def arch_version = "2.1.0"// ViewModelimplementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"// LiveDataimplementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"// 只有Lifecycles (不带 ViewModel or LiveData)implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"// Saved state module for ViewModelimplementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"// lifecycle注解处理器annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"// 替换 - 如果使用Java8,就用这个替换上面的lifecycle-compilerimplementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"//以下按需引入// 可选 - 帮助实现Service的LifecycleOwnerimplementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"// 可选 - ProcessLifecycleOwner给整个 app进程 提供一个lifecycleimplementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"// 可选 - ReactiveStreams support for LiveDataimplementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"// 可选 - Test helpers for LiveDatatestImplementation "androidx.arch.core:core-testing:$arch_version"}
​

②创建一个类实现LifecycleOwner:

public class MyLocationListener  implements LifecycleObserver {public MyLocationListener(Activity context, OnLocationChangeListener listener) {
​//初始化操作iniLocationManager();}private void iniLocationManager() {}//当Activity执行onResume()方法时,该方法会被自动调用@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)private  void startGetLocation(){Log.e("true","onResume"+"被调用了");}//当Activity执行onPause()方法时,该方法会被自动调用@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)private  void stopGetLocation(){Log.e("true","onPause"+"被调用了");}//当Activity执行onDestroy()方法时,该方法会被自动调用@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)private  void delGetLocation(){Log.e("true","onDestroy"+"被调用了");}//当地理位置发送改变时,通过该接口通知调用者public  interface  OnLocationChangeListener{void  onChanged(double latitude,double longitude);}
}
​

按照需求通过注解的方式来实现方法的调用。

③在需要被观察的activity或者fragment中添加Lifecycle对象,并且添加observer。 主MainActivity 在MainActivity中,只需要引用MyLocationListener即可,不用再关心Activity生命周期变化对该组件所带来的影响。生命周期的管理完全交给MyLocationListener内部自行处理。在Activity中要做的只是通过getLifecycle().addObserver()方法,将观察者与被观察者绑定起来,代码如下:

public class MainActivity extends AppCompatActivity {
​private  MyLocationListener myLocationListener;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myLocationListener = new MyLocationListener(this, new MyLocationListener.OnLocationChangeListener() {@Overridepublic void onChanged(double latitude, double longitude) {//展示收到的位置信息}});//将观察者与被观察者绑定getLifecycle().addObserver(myLocationListener);}
}

ViewModel

ViewModel是Jetpack AAC的重要组件,同时也有一个同名抽象类。 ViewModel,意为 视图模型,即为界面准备数据的模型。简单理解就是,ViewModel为UI层提供数据。

ViewModel使用:

①思路:

  • 导入依赖
  • 继承ViewModel自定义MyViewModel
  • 在MyViewModel中编写获取UI数据的逻辑
  • 使用LiveData将获取到的UI数据抛出
  • 在Activity/Fragment中使用ViewModelProvider获取MyViewModel实例
  • 观察MyViewModel中的LiveData数据,进行对应的UI更新。

举个例子,如果您需要在Activity中显示用户信息,那么需要将获取用户信息的操作分放到ViewModel中,代码如下:

public class UserViewModel extends ViewModel {
​private MutableLiveData<String> userLiveData ;private MutableLiveData<Boolean> loadingLiveData;public UserViewModel() {userLiveData = new MutableLiveData<>();loadingLiveData = new MutableLiveData<>();}//获取用户信息,假装网络请求 2s后 返回用户信息public void getUserInfo() {loadingLiveData.setValue(true);new AsyncTask<Void, Void, String>() {@Overrideprotected void onPostExecute(String s) {loadingLiveData.setValue(false);userLiveData.setValue(s);//抛出用户信息}@Overrideprotected String doInBackground(Void... voids) {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}String userName = "AAAAAABBBBBBBBBBBBCCCCCCCCC";return userName;}}.execute();}public LiveData<String> getUserLiveData() {return userLiveData;}public LiveData<Boolean> getLoadingLiveData() {return loadingLiveData;}
}
​

UserViewModel继承ViewModel,然后逻辑很简单:假装网络请求 2s后 返回用户信息,其中userLiveData用于抛出用户信息,loadingLiveData用于控制进度条显示。

再看UI层:

public class UserActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);...Log.i(TAG, "onCreate: ");
​TextView tvUserName = findViewById(R.id.textView);ProgressBar pbLoading = findViewById(R.id.pb_loading);//获取ViewModel实例ViewModelProvider viewModelProvider = new ViewModelProvider(this);UserViewModel userViewModel = viewModelProvider.get(UserViewModel.class);//观察 用户信息userViewModel.getUserLiveData().observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {// update ui.tvUserName.setText(s);}});userViewModel.getLoadingLiveData().observe(this, new Observer<Boolean>() {@Overridepublic void onChanged(Boolean aBoolean) {pbLoading.setVisibility(aBoolean?View.VISIBLE:View.GONE);}});//点击按钮获取用户信息findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {userViewModel.getUserInfo();}});}@Overrideprotected void onStop() {super.onStop();Log.i(TAG, "onStop: ");}@Overrideprotected void onDestroy() {super.onDestroy();Log.i(TAG, "onDestroy: ");}
}
​
​

页面有个按钮用于点击获取用户信息,有个TextView展示用户信息。 在onCreate()中先 创建ViewModelProvider实例,传入的参数是ViewModelStoreOwner,Activity和Fragment都是其实现。然后通过ViewModelProvider的get方法 获取ViewModel实例,然后就是 观察ViewModel中的LiveData。

②总结:

  • ViewModel的使用很简单,作用和原来的Presenter一致。只是要结合LiveData,UI层观察即可。
  • ViewModel的创建必须通过ViewModelProvider。
  • 注意到ViewModel中没有持有任何UI相关的引用。
  • 旋转手机重建Activity后,数据确实恢复了。

LiveData

LiveData是Jetpack提供的一种响应式编程组件,它可以包含任何类型的数据,并在数据发生变化的时候通知给观察者,适合与ViewModel结合在一起使用,就可以让ViewModel将数据的变化主动通知给Activity。

LiveData的使用

在开发中我们比较常用的就是 MutableLiveData ,他给我们暴露好了修改对应值的方法,LiveData的作者认为我们有这个功能就够了。

public class MutableLiveData<T> extends LiveData<T> {public MutableLiveData(T value) {super(value);}public MutableLiveData() {super();}// 在子线程 中 更改数据 就需要用到postValue方法@Overridepublic void postValue(T value) {super.postValue(value);}@Overridepublic void setValue(T value) {super.setValue(value);}
}

一个简单的 使用MutableLiveData的实例

class LiveDataTestActivity : AppCompatActivity() {val TAG = "LiveDataTestActivity"var index = 1val liveData:MutableLiveData<String> by lazy {MutableLiveData<String>().also {it.value = "周杰伦"}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)var binding = ActivityLiveDataTestBinding.inflate(layoutInflater)setContentView(binding.root)
​liveData.observe(this){Log.e(TAG,it)}}fun changeLivaData(view: View) {liveData.value = "周杰伦${index++}"}
}

首先调用liveData.observe注册一个观察者,观察者注册商后,用户点击xml上的按钮,liveData 会调用setValue方法(因为是kotlin省略了set) 然后在observe的回调中会打印对应的值,那么我们看看这个最终是怎么通知观察者 回调的呢。liveData调用了setValue方法,最后是调到Super了,也就是LiveData中的setValue方法。

DataBinding

DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,他的目的是一个帮助我们实现数据和UI绑定,并可以进行双向绑定。

优势

  1. 项目更加简介,代码可读性更高。
  2. 不再需要findViewById()。
  3. 布局文件可以包含简单的业务逻辑。

DataBinding使用

实例化布局文件了,我们删除掉传统的setContentView(),通过 DataBindingUtil.setContentView()来实例化文件。实例化返回的布局文件对象,名字和布局文字名字一致,遵循大驼峰命名规则,后面加上Binding。然后通过binding对象得到控件,控件命名遵循小驼峰规则。

ActivityMainBinding binding=DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.textHome.setText("hello databinding!");

数据绑定

如何将数据传递到布局文件中呢?首先,在布局文件中定义布局变量,指定对象的名字和类型,当然数据的操作在标签里。data标签里用于放在布局文件中各个UI控件所需要的数据,这些数据类型可以是自定义类型,也可以是基本类型。

<data>
​<variablename="book"type="com.yhj.jetpackstudy.Book" /><variablename="number"type="Integer" />
​
</data>
public class Book {
​private int id;private String title;private String author;
​
}

有时我们需要在布局文件中引入一些Java工具类或静态类,处理一些简单的逻辑在布局中,我们可以使用标签导入。使用alias,当类名有冲突时,其中一个类可使用别名重命名。默认导入java.lang.*

<data>    <import type="com.yhj.jetpackstudy.ui.home.Constants"alias="reName"/>
</data>

布局中的数据绑定使用“@{}”语法写入属性中,通过布局表达式的形式设置TextView的text。

<TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{book.title}" /><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{Constants.APP_ID}" />

DataBinding为了方便使用,对布局变量提供了Setter类,因此,在Activity中,通过setBook(),将Book对象传递给布局变量。

Book book = new Book(0, "android", "yhj");
//BR类似于Android中的R类,由DataBinding自动生成,用于存放所有布局变量的id。
//DataBinding为了方便使用提供了Setter类,直接使用setXxx()
//binding.setVariable(BR.book,book);
binding.setBook(book);

绑定后,就不需要再Activity中设置内容了,实现了布局与页面的解耦。 DataBinding具有Null校验,如果绑定值为null,则分配默认值null,如果类型为int,默认值为0。

本文主要讲了在Android jetpack中的重要组件,更多的jetpack技术请参考《jetpack技术与Android架构精讲》点击可查看详细类目。

最后

在我们工作中,可维护、可扩展、可测试和可重用的业务架构对于提高应用程序的质量和效率意义非凡,而JetPack是帮助开发者快速地组织和管理应用程序的代码的工具包。希望这篇文章能够让大家了解到jetpack的重要性

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

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

相关文章

微服务容错 Resilience4j 接口服务-容错原理

微服务容错 Resilience4j 容错原理 4.1 微服务容错简介 在⾼并发访问下&#xff0c;⽐如天猫双11&#xff0c;流量持续不断的涌⼊&#xff0c;服务之间的相互调⽤频率突然增加&#xff0c;引发系统负载过⾼&#xff0c;这时系统所依赖的服务的稳定性对系统的影响⾮常⼤&#…

0301yarnmapredude入门-hadoop-大数据学习

文章目录 1 MapReduce概述2 YARN2.1 yarn概述2.2 yarn与MapReduce关系2.3 yarn架构2.4 辅助角色 3 MapReduce & YARN部署3.1 集群规划3.2 配置文件3.3 分发配置文件 4 体验4.1 集群启动命令介绍4.2 提交MapReduce任务到YARN执行 结语 1 MapReduce概述 分布式计算是一种计算…

过滤器的应用-Filter

过滤器 1.工作原理 2.创建Filter 2.1通过注解的方式实现 //创建一个类&#xff0c;实现Filter接口 WebFilter(urlPatterns "/myfilter") //urlPatterns表示需要拦截的路径 public class MyFilter implements Filter {Overridepublic void doFilter(ServletReques…

WebRTC音视频通话-WebRTC推拉流过程中日志log输出

WebRTC音视频通话-WebRTC推拉流过程中日志log输出 之前实现iOS端调用ossrs服务实现推拉流流程。 推流&#xff1a;https://blog.csdn.net/gloryFlow/article/details/132262724 拉流&#xff1a;https://blog.csdn.net/gloryFlow/article/details/132417602 在推拉流过程中的…

并发-Java中的锁(四)---LockSupport工具,Condition

LockSupport工具 当需要阻塞或唤醒一个线程的时候&#xff0c;都会使用LockSupport工具类来完成相应工作定义了一组公共静态方法&#xff0c;提供了最基本的线程阻塞和唤醒功能定义了一组以park开头的方法用来阻塞当前线程&#xff0c;unpark方法来唤醒一个被阻塞线程 void pa…

ssh 基本用法与免密登录

基本用法 远程连接服务器&#xff1a; ssh userhostname user&#xff1a;用户名hostname&#xff1a;IP地址或域名 举个例子&#xff0c;假设我们的user是tom&#xff0c;hostname是123.45.67.890 可以输入&#xff1a;ssh tom123.45.67.890 第一次登陆时会提示&#xff1a…

arm64架构的linux中断分析

文章目录 1. 中断的概念和作用2. Linux中断处理机制2.1 中断请求2.2 中断处理2.3 中断完成2.4.中断触发和处理步骤详解2.4.1 异常向量表的解读 3. GICv3中断控制器3.1 GICv3中断控制器设备树3.2 GICv3中断控制器驱动 4. GIC的下一级中断控制器4.1 设备树4.2 内核对设备树的处理…

大数据学习:Hive常用函数

Hive常用函数 1. Hive的参数传递 1.1 Hive命令行 查看hive命令的参数 [hadoopnode03 ~]$ hive -help语法结构: hive [-hiveconf xy]* [<-i filename>]* [<-f filename>|<-e query-string>][-S] 说明&#xff1a; -i 从文件初始化HQL。-e从命令行执行指定…

线性代数的学习和整理16:什么是各种空间(类型),向量空间,距离(类型)?

目录 1 空间相关的群&#xff0c;环&#xff0c;域&#xff0c;集合&#xff0c;空间的预备知识 1.1&#xff1a;群&#xff0c;环&#xff0c;域&#xff0c;集合&#xff0c;空间的定义&#xff08;表示不懂&#xff0c;只是做个标记&#xff09; 2 空间 2.1 各种空间概念…

WebRTC-Streamer交叉编译

WebRTC-Streamer交叉编译 flyfish 文章目录 WebRTC-Streamer交叉编译零、前言一、提前准备工作1 安装需要的工具2 可选的交叉编译工具3 默认执行python是python34 获取源码5 使用其他版本的方法 二、非交叉编译编译1 在 src目录执行 安装所需的依赖2 执行命令 三、 交叉编译1 …

css如何给盒子底部加阴影,CSS3 --添加阴影(盒子阴影、文本阴影的使用)

CSS3 - 给div或者文字添加阴影(盒子阴影、文本阴影的使用) CSS3定义了两种阴影&#xff1a;盒子阴影和文本阴影。其中盒子阴影需要IE9及其更新版本&#xff0c;而文本阴影需要IE10及其更新版本。下面分别介绍两种阴影的使用&#xff1a; 1&#xff0c;盒子阴影 (1)盒子阴影的…

Java-集合-ConcurrentHashMap

table&#xff1a;数组加volatile保证可见性和有序性 put()&#xff1a;数组不存在&#xff0c;通过CAS创建&#xff1b;数组下标位置为空&#xff0c;通过CAS插入&#xff1b;数组下标位置不为空&#xff0c;给头节点加synchronized来插入链表或红黑树 面试题 ConcurrentHas…

【Linux】redhat7.8配置yum在线源【redhat7.8镜像容器内配置yum在线源】通用

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

【车载以太网测试从入门到精通】——DoIP BootLoader刷写测试(含CAPL源码)

系列文章目录 文章目录 系列文章目录前言一、DoIP刷写环境搭建二、DoIP刷写工程使用方法三、DoIP刷写CAPL源码四、刷写工程下载链接前言 DoIP概述: DoIP(Diagnostic communication over InternetProtocol),基于IP网络的汽车诊断协议。DoIP技术可实现本地诊断、远程诊断、空…

Navicat 强大的数据模型功能 | 面向数据库设计、架构和数据资产梳理等使用场景

数据模型是用来描述数据、组织数据和对数据进行操作的一组概念和定义。根据不同的应用需求&#xff0c;数据模型可以分为概念模型、逻辑模型和物理模型。这些数据模型帮助数据库设计人员设计和管理数据库&#xff0c;以满足用户的需求。 Navicat 强大的数据模型功能主要适用于…

软件定义网络:重新定义云计算网络架构

文章目录 软件定义网络的基本概念软件定义网络的工作原理软件定义网络在云计算中的应用与优势示例&#xff1a;软件定义网络配置未来发展和挑战结论 &#x1f389;欢迎来到AIGC人工智能专栏~软件定义网络&#xff1a;重新定义云计算网络架构 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&a…

贷款公司如何精准获客,大数据获客

近年来&#xff0c;贷款中介机构在金融服务领域发挥着越来越重要的作用。随着时代的发展&#xff0c;贷款中介机构不仅是贷款服务的提供者&#xff0c;也是能够帮助客户更准确获取客户的服务提供者。 为此&#xff0c;贷款中介机构应把握以下几个方面。 首先&#xff0c;贷款…

Vue中引入一个异步组件

在Vue中引入异步组件可以通过动态导入&#xff08;Dynamic Import&#xff09;和异步组件工厂函数&#xff08;Async Component Factory Function&#xff09;来实现 方法一&#xff1a;动态导入 在Vue中&#xff0c;可以使用动态导入的方式引入异步组件。动态导入是ES2015的…

基于YOLOV8模型和CCPD数据集的车牌目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOV8模型和CCPD数据集的车牌目标检测系统可用于日常生活中检测与定位车牌目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算…

Win11 避坑安装WSL2 Ubuntu22.04

开始之前以管理员身份打开 PowerShell 启用适用于 Linux 的 Windows 子系统 需要先启用“适用于 Linux 的 Windows 子系统”可选功能&#xff0c;然后才能在 Windows 上安装 Linux 分发。 PowerShell然后输入以下命令&#xff1a; dism.exe /online /enable-feature /featur…