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对象
name="viewmodel"
type="com.android.example.livedatabuilder.livedataviewmodel" />
...
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 create(modelclass: class): t {
@suppress("unchecked_cast")
return livedataviewmodel(datasource) as t
}
}
注意:此处构造viewmodel采用的datasource为defaultdatasource,后续数据是根据此数据源来进行获取的。
系统时间(long型)显示
系统时间的显示,通过在ui上绑定viewmodel,通过getcurrenttime方法后台更新、提交数据,来通知ui进行显示的更新。
//xml
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秒
}
}
系统时间显示
系统时间的显示是根据系统获取的long型变量变化映射得到的,long值发生变化时,实时更新系统时间显示。
//xml
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()
}
天气显示
天气的显示通过动态改变数据源提供的数据,从而通知ui显示(datasource数据的更新实时通过livedata传递到ui)。
//xml
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])
}
}
远端数据显示
远端数据的请求通过button的点击事件触发,数据获取成功后,通知textview进行数据显示。
//xml
android:id="@+id/cached_value"
android:text="@{viewmodel.cachedvalue}"
.../>
android:id="@+id/refresh_button"
android:οnclick="@{() -> 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"//返回此字符串
}
小提示:本例中的viewmodelscope使用的是kotlin coroutines(协程)功能,更多协程使用方法,请查看coroutines在架构组件中的应用:
远端数据的更新流程为:
将上述四个控件分别绑定对应的livedata对象,增加其数据变化,就能够实现前文描述的app动态变化效果了。
小技巧: github 代码下载速度慢,可以克隆到码云上(gitee.com)再下载。
通过这四个控件的livedata与ui的交互使用,你学会如何使用livedata了吗?
欢迎关注公众号,留言讨论更多技术问题。
如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!