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<activitylivedatabinding>( 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>): t { @suppress("unchecked_cast") return livedataviewmodel(datasource) as t } }
注意:此处构造viewmodel采用的datasource为defaultdatasource,后续数据是根据此数据源来进行获取的。
系统时间(long型)显示
系统时间的显示,通过在ui上绑定viewmodel,通过getcurrenttime方法后台更新、提交数据,来通知ui进行显示的更新。
//xml <textview android:id="@+id/time" android:text="@{long.tostring(viewmodel.currenttime)}" .../> //livedataviewmodel val currenttime = datasource.getcurrenttime() //defaultdatasource override fun getcurrenttime(): livedata<long> = livedata { while (true) { emit(system.currenttimemillis())//通知当前系统时间 delay(1000)//延时1秒 } }
系统时间显示
系统时间的显示是根据系统获取的long型变量变化映射得到的,long值发生变化时,实时更新系统时间显示。
//xml <textview android:id="@+id/time_transformed" android:text="@{viewmodel.currenttimetransformed}" .../> //livedataviewmodel 此处有两种方式实现 //1. currenttime变更后实时通知ui更新 val currenttimetransformed : livedata<string> = 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 <textview android:id="@+id/current_weather" android:text="@{viewmodel.currentweather}" .../> //livedataviewmodel val currentweather: livedata<string> = livedata { emit(loading_string) emitsource(datasource.fetchweather()) } //defaultdatasource private val weatherconditions = listof("sunny", "cloudy", "rainy", "stormy", "snowy") override fun fetchweather(): livedata<string> = livedata { var counter = 0 while (true) { counter++ delay(2000)//延时两秒 //按顺序循环显示weatherconditions中的天气数据信息 emit(weatherconditions[counter % weatherconditions.size]) } }
远端数据显示
远端数据的请求通过button的点击事件触发,数据获取成功后,通知textview进行数据显示。
//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<string> = _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了吗?