Jetpack:LiveData入门指南

又到周末好时光,茫茫人海中,与你在掘金相遇,好幸运~请君赏阅本文,相处不易,开门见山,不扯皮。本文讲的是Jetpack系列第三个架构组件LiveData,LiveData是Lifecycle-aware 组件的一个应用,这意味着LiveData遵照Activity、Fragment和Service等组件的生命周期,在它们生命周期处于活跃状态(CREATEDRESUMED)才进行更新Views。java

使用LiveData步骤

  1. 建立持有某种类型的LiveData对象。一般在ViewModel类来实现该对象。
  2. 定义一个具备onChanged()方法的Observer对象,当LiveData持有数据变化是回调该方法。一般在UI控制器类中实现建立该Observer对象,如Activity或Fragment。
  3. 经过使用observe()方法,将上述的LiveData对象和Observer对象关联在一块儿。这样Observer对象就与LiveData产生了订阅关系,当LiveData数据发生变化时通知,而在Observer更新数据,因此Observer一般是Activity和Fragment。

三个步骤就定义了使用LiveData的方式,从步骤能够看出,使用了观察者模式,当LiveData对象持有数据发生变化,会通知对它订阅的全部处于活跃状态的订阅者。而这些订阅者一般是UI控制器,如Activity或Fragment,以能在被通知时,自动去更新Views。android

建立LiveData对象

LiveData能够包装任何数据,包括集合对象。LiveData一般存储在ViewModel中,并经过getter方法得到。示例:git

class NameViewModel : ViewModel() {

    // Create a LiveData with a String
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...
}
复制代码

为何是ViewModel持有LiveData而不是Activity或者Fragment中呢?github

  • 这样致使Activity或Fragment代码臃肿,Activity或Fragment通常用来展现数据而不是持有数据。
  • 将LiveData解耦,不和特定的Activity或Fragment绑定在一块儿。

建立 观察LiveData 的对象

有了数据源以后,总须要有观察者来观察数据源,否则数据源就失去了存在的意义。数据库

那么在哪里观察数据源呢?设计模式

在大多数状况下,在应用组件的onCreate()方法中访问LiveData是个合适的时机。这样能够确保系统不在Activity或Fragment的onResume()方法进行多余的调用;另外这样也确保Activity和Fragment尽早有数据能够进行显示。bash

class NameActivity : AppCompatActivity() {

    private lateinit var model: NameViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Get the ViewModel.
        model = ViewModelProviders.of(this).get(NameViewModel::class.java)


        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView. 
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)
    }
}
复制代码

在讲nameObserver对象传给observe()方法后,存储在LiveData最近的值以参数的形式当即传递到onChange()方法中。固然,若是此时LiveData没有存储值的话,onChange()方法不会被调用。服务器

更新 LiveData 对象

LiveData自己没有提供公共方法更新值。若是须要修改LiveData的数据的话,能够经过MutableLiveData来暴露共有方法setValue()postValue()。一般在在ViewModel中使用MutableLiveData,而MutableLiveData暴露不可变的LiveData给Observer。与Observer创建关系后,经过修改LiveData的值从而更新Observer中的视图。网络

button.setOnClickListener {
    val anotherName = "GitCode"
    model.currentName.setValue(anotherName)
}
复制代码

当单击button时,字符串GitCode会存储到LiveData中,nameTextView的文本也会更新为GitCode。这里经过button的点击来给LiveData设置值,也能够网络或者本地数据库获取数据方式来设置值。架构

扩展 LiveData

能够经过下面的栗子来看看如何扩展LiveData。

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }
}
复制代码

首先创建一个StockLiveData并继承自LiveData,并重写两个重要方法。

  • onActivite() 当有活跃状态的订阅者订阅LiveData时会回调该方法。意味着须要在这里监听数据的变化。
  • onInactive() 当没有活跃状态的订阅者订阅LiveData时会回调该方法。此时没有必要保持StockManage服务象的链接。
  • setValue() 注意到value=price这里是调用了setValue(price)方法,经过该方法更新LiveData的值,进而通知处于活跃状态的订阅者。

LiveData会认为订阅者的生命周期处于STARTEDRESUMED状态时,该订阅者是活跃的。

那么如何使用StockLiveData呢?

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    val myPriceListener: LiveData<BigDecimal> = ...
    myPriceListener.observe(this, Observer<BigDecimal> { price: BigDecimal? ->
        // Update the UI.
    })
}
复制代码

以Fragment做LifecycleOwner的实例传递到observer()方法中,这样就将Observer绑定到拥有生命周期的拥有者。因为LiveData能够在多个Activity、Fragment和Service中使用,因此能够建立单例模式。

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager: StockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }

    companion object {
        private lateinit var sInstance: StockLiveData

        @MainThread
        fun get(symbol: String): StockLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        }
    }
}
复制代码

那么在Fragment能够这样使用:

class MyFragment : Fragment() {

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })

    }
复制代码

转换 LiveData

有时候在把数据分发给Observer前,转换存储在LiveData中的值,或者返回一个 基于已有值的LiveData对象 的另一个LiveData对象。这时候就须要用到 Transformations类来处理了。

使用Transformations.map()方法能够改变其下游的结果:

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});
复制代码

使用Transformations.switchMap()一样能够改变下游的结果,但传递给switchMap()的函数必须返回一个LiveData对象。

private fun getUser(id: String): LiveData<User> {
  ...
}
val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId) { id -> getUser(id) }
复制代码

这种转换方式都惰性的,也就是只有Observer来订阅数据的时候,才会进行转换。当在ViewModel须要一个Lifecycle对象,或许这种转换会是很好的解决方案。

合并多个LiveData 源

MediatorLiveData是LiveData的子类,它主要用途是用来合并多个LiveData源。当其中一个源数据发生变化是,都会回调订阅MediatorLiveData的观察者的onChanged()方法。例如咱们在实际开发中,咱们的数据源要么来自服务器,要么来自本地数据库。这里就考虑使用MediatorLiveData。

更多信息请参阅官网

总结

LiveData的入门使用来讲仍是相对简单的,等到后面讲完Jetpack系列文章,再以一个综合的Demo示例Jetpack涉及到的一些知识点。光看文档,均可以感受到Android 对设计模式,和MVP模式、MVVM模式设计理念使用得淋漓尽致。因此建议各位同窗在代码方面的编写必定要有大局观念,代码规范的仍是要有,方便别人就是方便本身。不要为应付功能实现而代码臃肿,后续又不从新架构,一直积累成垃圾码。

Welcom to visit my github

本文是Jetpack系列文章第三篇

第一篇: Jetpack:你还在findViewById么?

第二篇:Jetpack:你如何管理Activity和Fragment的生命周期?

相关文章
相关标签/搜索