Jetpack系列:LiveData入門級使用方法

Android APP開發中,開發者們都想有一個公共的組件,能夠實現後臺數據的監聽,同時實時更新到UI進行顯示,從而大大簡化開發過程。Google針對這一開發需求,提供了Jetpack LiveData組件。下面咱們來一塊兒看下LiveData的基本使用方法吧!android

首先,先了解下使用LiveData的優勢。git

  • 確保UI與數據狀態匹配
  • 不須要擔憂內存泄漏問題
  • Activity中止後數據變化不會致使Crash
  • 再也不須要人工生命週期的處理
  • 始終使用最新的數據
  • 正確應用配置更改
  • 共享資源

LiveData遵循觀察者模式,實現LifeCycle接口,所以能夠監聽數據的實時更新,感知應用的生命週期,讓開發者可以更多的關注業務具體實現。github

下面咱們來經過一個小Demo來簡單介紹下LiveData的基本使用方法。


file架構


本例中,數據變化通知UI的顯示由四個控件體現,分別爲:系統時間(Long型)、系統時間、天氣、遠端數據。針對這四個控件的動態顯示,咱們分別來看下其是如何實現的。app

框架搭建



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進行顯示的更新。

ide

//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)。

fetch

//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進行數據顯示。

gradle

//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在架構組件中的應用:官方文檔連接



遠端數據的更新流程爲:

file


將上述四個控件分別綁定對應的LiveData對象,增長其數據變化,就可以實現前文描述的APP動態變化效果了。



幫助文檔

源碼路徑

小技巧: github 代碼下載速度慢,能夠克隆到碼雲上(gitee.com)再下載。


經過這四個控件的LiveData與UI的交互使用,你學會如何使用LiveData了嗎?



歡迎關注公衆號,留言討論更多技術問題
file

相關文章
相關標籤/搜索