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)
setValue(T value)
postValue(T value)
observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
observeForever(@NonNull Observer<? super T> observer)
removeObservers(@NonNull final Observer<? super T> observer)
onActive()
onInactive()
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继承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内部原理使用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的用法