Android APP開發中,開發者們都想有一個公共的組件,可以實現後臺數據的監聽,同時實時更新到UI進行顯示,從而大大簡化開發過程。Google針對這一開發需求,提供了Jetpack LiveData組件。下麵我們來一起看下LiveData的基本使用方法吧! 首先,先瞭解下使用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了嗎?