Android Architecture Components 之 LiveData

LiveData

LiveData 是一个数据持有类,它持有一个值并且该值可以被观察。不同于普通的可观察者,LiveData 遵从应用组件的生命周期,这样 Observer 便可以指定一个其应该遵循的 Lifecycle。

如果 Observer 所依附的 Lifecycle 处于 STARTED 或者 RESUMED 状态,则 LiveData 认为 Observer 处于活跃状态。

  • 避免内存泄露:因为 Observer 是绑定到 Lifecycle 对象上的,当 Lifecycle 对象被销毁的时候,LiveData 对象也会被自动清除

  • 资源共享:通过单例模式,可以在多个 Activity 或者 Fragment 之间共享 LiveData 数据。

  • 不再手动的处理生命周期:Fragment 只有在处于活跃的时候才会观察 LiveData 数据。由于 Fragment 提供了 Lifecycle 对象,所以 LiveData 会管理这一切

  • 始终保持最新的数据:如果一个 Lifecycle 重新启动以后(例如:Activity 从后台重新开始运行于前台),它会接收到最新的数据(除非没有最新的数据)

  • 正确处理配置改变:如果一个 Activity 或者 Fragment 以为配置改变(例如:旋转屏幕)被重建以后,LiveData 将会接收到最新的数据

  • 不会因为 Activity 停止而使应用崩溃:如果 Observer 所绑定的 Lifecycle 处于闲置状态(例如:Activity 处于后台运行时),他们不会接收到改变的事件

LiveData和MutableLiveData的区别

LiveData没有setValue方法,所以用MutableLiveData

setValue和postValue的区别

setValue只能在main线程调用,postValue可以在子线程调用

问题

视图层(Activity 或者 Fragment)与 ViewModel 层进行通讯的一种便捷的方式就是使用 LiveData 来进行观察。这个视图层订阅 Livedata 的数据变化并对其变化做出反应。这适用于连续不断显示在屏幕的数据.

但是,有一些数据只会消费一次,就像是 Snackbar 消息,导航事件或者对话框。

解决方案

SingleLiveEvent

/**
 * A lifecycle-aware observable that sends only new updates after subscription, used for events like
 * navigation and Snackbar messages.
 *
 *
 * This avoids a common problem with events: on configuration change (like rotation) an update
 * can be emitted if the observer is active. This LiveData only calls the observable if there's an
 * explicit call to setValue() or call().
 *
 *
 * Note that only one observer is going to be notified of changes.
 */
class SingleLiveEvent : MutableLiveData() {
​
    private val pending = AtomicBoolean(false)
​
    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer) {
​
        if (hasActiveObservers()) {
//            Log.d("SingleLiveEvent","Multiple observers registered but only one will be notified of changes.")
        }
​
        // Observe the internal MutableLiveData
        super.observe(owner, Observer { t ->
            if (pending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }
​
    @MainThread
    override fun setValue(t: T?) {
        pending.set(true)
        super.setValue(t)
    }
​
    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() {
        value = null
    }
}

问题 : SingleLiveEvent 的问题在于它仅限于一个观察者。如果您无意中添加了多个,则只会调用一个,并且不能保证哪一个

AtomicBoolean

AtomicBoolean,在这个Boolean值的变化的时候不允许在之间插入,保持操作的原子性。方法和举例:compareAndSet(boolean expect, boolean update)。这个方法主要两个作用         1. 比较AtomicBoolean和expect的值,如果一致,执行方法内的语句。其实就是一个if语句         2. 把AtomicBoolean的值设成update         比较最要的是这两件事是一气呵成的,这连个动作之间不会被打断,任何内部或者外部的语句都不可能在两个动作之间运行。为多线程的控制提供了解决的方案

val pending = AtomicBoolean(false)
if (pending.compareAndSet(true, false)) {
                observer.onChanged(t)
}
1:比较pending(是false)和expect(true)是否一致,以上pending.compareAndSet(true, false)是不一致,所以pending.compareAndSet(true, false)为false,不走if里面
2:如果pending.compareAndSet(false, true)
    比较pending(是false)和expect(false)是否一致,以上pending.compareAndSet(true, false)是一致,所以pending.compareAndSet(true, false)为true,并且pending会置为update(true),再走if里面

通过事件包装器

/**
 * Used as a wrapper for data that is exposed via a LiveData that represents an event.
 */
open class Event(private val content: T) {
​
    var hasBeenHandled = false
        private set // Allow external read but not write
​
    /**
     * Returns the content and prevents its use again.
     */
    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }
​
    /**
     * Returns the content, even if it's already been handled.
     */
    fun peekContent(): T = content
}
class ListViewModel : ViewModel {
    private val _navigateToDetails = MutableLiveData>()
​
    val navigateToDetails : LiveData>
        get() = _navigateToDetails
​
​
    fun userClicksOnButton(itemId: String) {
        _navigateToDetails.value = Event(itemId)  // Trigger the event by setting a new Event as a new value
    }
}
myViewModel.navigateToDetails.observe(this, Observer {
    it.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
        startActivity(DetailsActivity...)
    }
})

这种方法的优点在于用户使用 getContentIfNotHandled() 或者 peekContent() 来指定意图。这个方法将事件建模为状态的一部分:他们现在只是一个消耗或者不消耗的消息。

使用事件包装器,您可以将多个观察者添加到一次性事件中。

你可能感兴趣的:(Android,Architecture,Component,LiveData,Android,Architecture,Component,LiveData)