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() 来指定意图。这个方法将事件建模为状态的一部分:他们现在只是一个消耗或者不消耗的消息。

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

更多相关文章

  1. android中数据库创建操作的模式
  2. Android与单片机的信息传输方案
  3. Android(安卓)小项目之--Mini音乐播放器【简单版】(附源码)
  4. Android与MVC设计模式
  5. 通过Html网页调用本地安卓(android)app程序代码
  6. Android中各种Adapter的使用方法
  7. eclipse 和 Android(安卓)studio:SHA1和MD5证书指纹数据获取
  8. Android系列之GreenDao数据升级和加密(三)
  9. android sqlite 基本操作

随机推荐

  1. ViewModel+LiveData
  2. Activity切换导致的onCreate重复执行[转]
  3. Qt Android(安卓)QScreen 屏幕旋转功能
  4. Android(安卓)属性动画(Property Animatio
  5. 安卓开发----TextView控件属性列表
  6. CSS 3模仿android 中的toast效果
  7. Android(安卓)Suspend/resume 过程分析.
  8. android 实现图片的边框
  9. Android学习之Animation(一)
  10. Android(安卓)4.2官方文档chm格式下载