Jetpack系列:LiveData入门级使用方法
Android APP开发中,开发者们都想有一个公共的组件,可以实现后台数据的监听,同时实时更新到UI进行显示,从而大大简化开发过程。Google针对这一开发需求,提供了Jetpack LiveData组件。下面我们来一起看下LiveData的基本使用方法吧!
首先,先了解下使用LiveData的优点。
确保UI与数据状态匹配
不需要担心内存泄漏问题
Activity停止后数据变化不会导致Crash
不再需要人工生命周期的处理
始终使用最新的数据
正确应用配置更改
共享资源
LiveData遵循观察者模式,实现LifeCycle接口,因此可以监听数据的实时更新,感知应用的生命周期,让开发者能够更多的关注业务具体实现。
下面我们来通过一个小Demo来简单介绍下LiveData的基本使用方法。

本例中,数据变化通知UI的显示由四个控件体现,分别为:系统时间(Long型)、系统时间、天气、远端数据。针对这四个控件的动态显示,我们分别来看下其是如何实现的。
框架搭建
APP首先需要搭建使用LiveData的环境:
1. 导入依赖包
//app build.gradle
dependencies {
...
implementation deps.lifecycle.viewmodel_ktx
implementation deps.lifecycle.livedata_ktx
...
}
## 2. 创建ViewModel类(用于LiveData数据的封装,和UI交互)
```
class LiveDataViewModel(
private val dataSource: DataSource
) : ViewModel() {...}
```
## 3. 布局文件中引用ViewModel对象
<layout>
<data>
<variable
name="viewmodel"
type="com.android.example.livedatabuilder.LiveDataViewModel" />
</data>
...
</layout>
## 4. Activity绑定ViewModel
```
//MainActivity
//成员变量
private val viewmodel: LiveDataViewModel by viewModels { LiveDataVMFactory }
//onCreate
val binding = DataBindingUtil.setContentView(
this, R.layout.activity_livedata
)
// Set the LifecycleOwner to be able to observe LiveData objects
binding.lifecycleOwner = this
// Bind ViewModel
binding.viewmodel = viewmodel
//LifeDataVMFactory
object LiveDataVMFactory : ViewModelProvider.Factory {
private val dataSource = DefaultDataSource(Dispatchers.IO)
override fun <T : ViewModel?> create(modelClass: Class): T {
@Suppress("UNCHECKED_CAST")
return LiveDataViewModel(dataSource) as T
}
}
<br/>
### 注意:此处构造ViewModel采用的dataSource为DefaultDataSource,后续数据是根据此数据源来进行获取的。
<br/>
# 系统时间(Long型)显示
<br/>
系统时间的显示,通过在UI上绑定ViewModel,通过getCurrentTime方法后台更新、提交数据,来通知UI进行显示的更新。
<br/>
//xml
<TextView
android:id="@+id/time"
android:text="@{Long.toString(viewmodel.currentTime)}"
.../>
//LiveDataViewModel
val currentTime = dataSource.getCurrentTime()
//DefaultDataSource
override fun getCurrentTime(): LiveData =
liveData {
while (true) {
emit(System.currentTimeMillis())//通知当前系统时间
delay(1000)//延时1秒
}
}
<br/>
# 系统时间显示
<br/>
系统时间的显示是根据系统获取的Long型变量变化映射得到的,Long值发生变化时,实时更新系统时间显示。
<br/>
//xml
<TextView
android:id="@+id/time_transformed"
android:text="@{viewmodel.currentTimeTransformed}"
.../>
//LiveDataViewModel 此处有两种方式实现
//1. currentTime变更后实时通知UI更新
val currentTimeTransformed : LiveData = Transformations.map(currentTime) {
Date(it).toString()
}
//2. 延时500ms后通知
val currentTimeTransformed = currentTime.switchMap {
// timeStampToTime is a suspend function so we need to call it from a coroutine.
liveData { emit(timeStampToTime(it)) }
}
private suspend fun timeStampToTime(timestamp: Long): String {
delay(500) // Simulate long operation
val date = Date(timestamp)
return date.toString()
}
<br/>
# 天气显示
<br/>
天气的显示通过动态改变数据源提供的数据,从而通知UI显示(DataSource数据的更新实时通过LiveData传递到UI)。
<br/>
//xml
<TextView
android:id="@+id/current_weather"
android:text="@{viewmodel.currentWeather}"
.../>
//LiveDataViewModel
val currentWeather: LiveData = liveData {
emit(LOADING_STRING)
emitSource(dataSource.fetchWeather())
}
//DefaultDataSource
private val weatherConditions = listOf("Sunny", "Cloudy", "Rainy", "Stormy", "Snowy")
override fun fetchWeather(): LiveData = liveData {
var counter = 0
while (true) {
counter++
delay(2000)//延时两秒
//按顺序循环显示weatherConditions中的天气数据信息
emit(weatherConditions[counter % weatherConditions.size])
}
}
<br/>
# 远端数据显示
<br/>
远端数据的请求通过Button的点击事件触发,数据获取成功后,通知TextView进行数据显示。
<br/>
//xml
<TextView
android:id="@+id/cached_value"
android:text="@{viewmodel.cachedValue}"
.../>
<Button
android:id="@+id/refresh_button"
android:onClick="@{() -> viewmodel.onRefresh()}"
.../>
//LiveDataViewModel
val cachedValue = dataSource.cachedData
fun onRefresh() {
// Launch a coroutine that reads from a remote data source and updates cache
viewModelScope.launch {
dataSource.fetchNewData()
}
}
//DefaultDataSource
private val _cachedData = MutableLiveData("This is old data")
override val cachedData: LiveData = _cachedData
override suspend fun fetchNewData() {
// Force Main thread
withContext(Dispatchers.Main) {
_cachedData.value = "Fetching new data..."
_cachedData.value = simulateNetworkDataFetch()
}
}
private var counter = 0
// Using ioDispatcher because the function simulates a long and expensive operation.
private suspend fun simulateNetworkDataFetch(): String = withContext(ioDispatcher) {
delay(3000)//延时3秒
counter++
"New data from request #$counter"//返回此字符串
}
<br/>
##### 小提示:本例中的viewModelScope使用的是Kotlin Coroutines(协程)功能,更多协程使用方法,请查看Coroutines在架构组件中的应用:[官方文档链接](https://developer.android.google.cn/topic/libraries/architecture/coroutines)[]()
<br/>
远端数据的更新流程为:<br/><br/>
<center>

</center>
<br/>
将上述四个控件分别绑定对应的LiveData对象,增加其数据变化,就能够实现前文描述的APP动态变化效果了。
<br/>
[帮助文档](https://developer.android.google.cn/topic/libraries/architecture/livedata)
 
[源码路径](https://github.com/android/architecture-components-samples)<br/><br/>
小技巧: github 代码下载速度慢,可以克隆到码云上(gitee.com)再下载。
<br/><br/>
通过这四个控件的LiveData与UI的交互使用,你学会如何使用LiveData了吗?
<br/><br/>
<center><font color='green'>欢迎关注公众号,留言讨论更多技术问题。</center>
<center>

</center>
Jetpack系列:LiveData入门级使用方法的更多相关文章
- iconfont 入门级使用方法
iconfont : what? 阿里妈妈MUX倾力打造的矢量图标管理.交流平台.设计师将图标上传到Iconfont平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师 ...
- Jetpack系列:应用内导航的正确使用方法
今天小编要分享的还是Android Jetpack库的基本使用方法,本篇介绍的内容是Jetpack Navigation组件,让我们一起学习,为完成年初制定的计划而努力吧! *** 组件介绍 导航,是 ...
- Google C++测试框架系列:入门
Google C++测试框架系列:入门 原始链接:V1_6_Primer 注 GTest或者Google Test: Google的C++测试框架. Test Fixtures: 这个词实在找不到对应 ...
- Python系列之入门篇——HDFS
Python系列之入门篇--HDFS 简介 HDFS (Hadoop Distributed File System) Hadoop分布式文件系统,具有高容错性,适合部署在廉价的机器上.Python ...
- Python系列之入门篇——MYSQL
Python系列之入门篇--MYSQL 简介 python提供了两种mysql api, 一是MySQL-python(不支持python3),二是PyMYSQL(支持python2和python3) ...
- 【转】C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。
C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子. 标签: c#objectnewlineexceptionbytestring 2010-05-17 01:10 117109人阅读 ...
- .NET 4 并行(多核)编程系列之一入门介绍
.NET 4 并行(多核)编程系列之一入门介绍 本系列文章将会对.NET 4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍. 本篇文章的议题如下: 1. 并行编程和多线程编程的区别. ...
- LINQ学习系列-----1.3 扩展方法
这篇内容继续接着昨天的Lambda表达式的源码继续下去.昨天讲了Lambda表达式,此篇讲扩展方法,这两点都是Linq带来的新特性. 一.扩展方法介绍 废话不多说,先上源码截图: 上图中Ge ...
- Pandas系列之入门篇
Pandas系列之入门篇 简介 pandas 是 python用来数据清洗.分析的包,可以使用类sql的语法方便的进行数据关联.查询,属于内存计算范畴, 效率远远高于硬盘计算的数据库存储.另外pand ...
随机推荐
- js获取Cookie,获取url参数
function getCookie(name) { var strCookie = document.cookie; var arrCookie = strCookie.split("; ...
- 微信小程序捕获async/await函数异常实践
背景 我们的小程序项目的构建是与web项目保持一致的,完全使用webpack的生态来构建,没有使用小程序自带的构建功能,那么就需要我们配置代码转换的babel插件如Promise.Proxy等:另外, ...
- mac入门之设置
mac入门: 一般手机软件,都是分设置和业务功能:操作系统亦是如此,设置+必备应用:用设置入门十分合理. 总览: 通用:通用,顾明思意是设置的设置,设置是独立应用之外或者公共的开关,通用更抽象一层,没 ...
- python接口自动化测试之requests库详解
前言 说到python发送HTTP请求进行接口自动化测试,脑子里第一个闪过的可能就是requests库了,当然python有很多模块可以发送HTTP请求,包括原生的模块http.client,urll ...
- GitHub 简单教程
码农朋友们都知道,GitHub是一个面向开源及私有软件项目的托管平台,上面托管了众多的优秀的项目,比如Linux内核源码.Git源码.机器学习框架Tensorflow等等.当然,除了这些顶尖项目外,还 ...
- 接口请求失败处理,重新请求并限制请求次数.自己封装搞定retry函数
最近开发一款小程序的时候想到一个问题,如果接口突然挂掉怎么办呢,于是乎想到一个解决办法.接口请求重试功能.并限制请求次数 用最新的async函数语法实现.代码简洁明了. 测试代码如下: functio ...
- axios跨域访问eggjs的坑egg-cors egg-passport passport-local session传递问题
在同一机器上写前端和后端,前端使用webpack-dev-server启动,后端直接在eggjs项目目录下使用npm run dev启动,这种情况下,前端访问后端就是跨域访问.eggjs提供了一个跨域 ...
- MySQL 数据库出现导入xls数据出现1062主从错误错误问题解决方案
今天把xls数据表导入MySQL数据库时发现出现1062错误 ,并且有20-700条数据一直导入不了所以开始找解决方案. 解决方案1: 数据库表设计问题导致相同字段的重复数据不能导入 解 ...
- Linux基础提高_系统性能相关命令
w 看系统的负载信息 用于显示已经登陆系统的用户列表,并显示用户正在执行的指令 uptime [root@localhost]#uptime 17:26:07 up 9:02, 3 users, lo ...
- Day004课程内容
本节主要内容: 1.列表List L = [1,'哈哈哈','吼吼',[1,8,0],('"我“,"叫","元","组"),”ab ...