LiveData用法介紹
LiveData是Android Jetpack里的一個組件庫,它具有感知activity和fragment生命周期的功能,使用觀察者模式設置數據并確保數據在activity和fragment正確的生命周期內更新ui,提升App性能,并防止app crash
先來看一個非常簡單的例子
class LiveDataActivity : AppCompatActivity() { var liveData: MutableLiveData<String>? = null var disposable: Disposable? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_livedata) liveData = MutableLiveData() // 觀察數據的變化,只有在界面可見的時候才會回調(即onStart或onResume狀態) liveData!!.observe(this, Observer { tv_text.text = it }) loadData() } override fun onDestroy() { super.onDestroy() disposable?.dispose() } private fun loadData() { disposable = Flowable.interval(1, 1, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe { // 更新數據 liveData?.value = it.toString() } } }
LiveData的用法非常簡單,首選new一個LiveData對象,然后通過observe方法添加一個Observer,并實現Observer接口的onChanged方法,最后在數據更新的時候使用livedata的setValue方法更新數據即可;調用setValue方法的時候,如果當前Activity處于onStart或onResume狀態,則會調用Observer的onChanged回調,否則先緩存數據,當Activity重新回到onStart或onResume狀態時,再調用Observer的onChanged回調(Activity destroy時 會自動remove Observer,所以不需要我們手動remove)
LiveData 幾個比較重要的方法介紹
setValue(T value)
- 必須在 UI Thread 中調用,更新數據,同時當Activity處于onStart或onResume狀態時會調用Observer的onChanged回調
postValue(T value)
- 跟setValue()一樣,唯一的區別就是可以 非UI Thread 中調用,然后通過handler post在UI Thread中回調
observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
- 這是一個非常常用的方法, 用于添加一個Observer,監聽數據的變化; LifecycleOwner 一般是activity 或 fragment對象,使其LiveData可以感知其生命周期,只有在onStart或onResume狀態時會調用Observer的onChanged回調, 在destroy時 remove Observer
observeForever(@NonNull Observer<? super T> observer)
- 跟observe方法差不多,唯一的區別是沒辦法感知activity 或 fragment生命周期;即只要有數據更新就立馬調用Observer的onChanged回調,并且需要手動remove Observer;這個方法對于Transformation(數據轉換)非常有用,下面會介紹到
removeObservers(@NonNull final Observer<? super T> observer)
- 這個方法很簡單,就是刪除某個observer
onActive()
- 這是LiveData的一個回調方法,當observer的數量由0變成1的時候,會調用
onInactive()
- 這是LiveData的一個回調方法,當observer的數量由1變成0的時候,會調用
MutableLiveData 介紹
MutableLiveData 比較簡單,一般沒什么特殊需求,用MutableLiveData就可以,他的源碼實現也非常簡單
public class MutableLiveData<T> extends LiveData<T> { @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); } }
只是將LiveData用protected修飾postValue和setValue的方法改成了public
用法就跟上面的demo一樣
MediatorLiveData 介紹
MediatorLiveData繼承MutableLiveData, 并提供addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged)方法監聽LiveData的數據更新,然后做一層處理或直接通知給最外層的Observer
先看一下源碼里的example, 只處理前10次數據的變化
LiveData<String> liveData1 = ...; var liveDataMerger = MediatorLiveData<String>() liveDataMerger.addSource(liveData1, object: Observer<String> { var count = 1 override fun onChanged(t: String) { count++ // 在這里更新liveDataMerger的數據;因此可以在這里對數據做一些額外的處理之后再更新 liveDataMerger.value = t if (count > 10) { liveDataMerger.removeSource(liveData1) } } })
同時它還可以監聽多個LiveData的變化
val liveData1 = MutableLiveData<String>() val liveData2 = MutableLiveData<String>() var liveDataMerger = MediatorLiveData<String>() liveDataMerger.addSource(liveData1, Observer { liveDataMerger.value = it }) liveDataMerger.addSource(liveData2, Observer { liveDataMerger.value = it }) // 只要liveData1和liveData2數據有更新就會通知Observer更新ui liveDataMerger.observe(this, Observer { tv_text.text = it })
其實MediatorLiveData最常用的用法是結合Transformation來使用,下面將介紹Transformation的用法
Transformation 轉換
Transformation內部原理使用MediatorLiveData實現的
有的時候我們需要對當前data 轉換成我們需要的另一種data
比如rxJAVA的map方法
Flowable.range(1, 10) .map { "index: $it" } .subscribe { }
再比如 kotlin自帶的map擴展方法
val list = listOf(1, 2, 3, 4).map { "index: $it" }
LiveData 也提供了類似的map功能
// 創建LiveData val userLiveData: LiveData<User> = MutableLiveData<User>() val userName: LiveData<String> = Transformations.map(userLiveData) { user -> "${user.name} ${user.lastName}" } //觀察數據的更新 userName.observe(this, Observer { tv_text.text = it }) ... // 更新數據 userLiveData.value = User("zhang", "san")
LiveData 也提供了switchMap方法轉換數據,它與map唯一的不同是將data轉換成一個LiveData<T>,因此在轉換過程中可以繼續做異步操作請求數據等,他跟rxjava的flatmap方法有點像
// 先使用room數據庫定義一個UserDao example @Dao abstract class UserDao { @Query("select * from tab_user where uid = :uid") abstract fun getById(uid: Long): LiveData<User> } ... private fun getUser(id: String): LiveData<User> { // 可以使用room數據查詢user對象 // return AppDataBase.getUserDao().getUser(id) // 你也可以發網絡請求查詢user對象 return object: LiveData<User>() { override fun onActive() { super.onActive() // 模擬網絡請求數據 Flowable.timer(3, TimeUnit.SECONDS) .subscribe { postValue(User("zhang", "san")) } } } } ... val userId: LiveData<String> = MutableLiveData<String>() val user = Transformations.switchMap(userId) { id -> getUser(id) } //觀察數據的更新 user.observe(this, Observer { tv_text.text = "${it.name} ${it.name}" }) ... // 更新數據 userId.value = "001"
LiveData使用起來比較簡單,功能就介紹到這里,建議查看一下官方demo 學習結合其它library的用法