jetpack之LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

引用自官方文档

使用LiveData的优势

使用LiveData又以下优势

1.确保界面符合数据状态

LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。

2.不会发生内存泄漏

观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

3.不会因 Activity 停止而导致崩溃

如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。

4.不再需要手动处理生命周期

界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

5.数据始终保持最新状态

如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

6.适当的配置更改

如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。

7.共享资源

您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。

LiveData的使用

    在开发中我们比较常用的就是 MutableLiveData ,他给我们暴露好了修改对应值的方法,LiveData的作者认为我们有这个功能 就够了

public class MutableLiveData<T> extends LiveData<T> {
    public MutableLiveData(T value) {
        super(value);
    }
    public MutableLiveData() {
        super();
    }
    // 在子线程 中 更改数据 就需要用到postValue方法
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }
    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

一个简单的 使用MutableLiveData的实例


class LiveDataTestActivity : AppCompatActivity() {
    val TAG = "LiveDataTestActivity"
    var index = 1
    val liveData:MutableLiveData<String> by lazy {
        MutableLiveData<String>().also {
            it.value = "周杰伦"
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var binding = ActivityLiveDataTestBinding.inflate(layoutInflater)
        setContentView(binding.root)

        liveData.observe(this){
            Log.e(TAG,it)
        }
    }

    fun changeLivaData(view: View) {
        liveData.value = "周杰伦${index++}"
    }
}

首先调用liveData.observe注册一个观察者,观察者注册商后,用户点击xml上的按钮,liveData 会调用setValue方法(因为是kotlin省略了set) 然后在observe的回调中会打印对应的值,那么我们看看这个最终是怎么通知观察者 回调的呢。liveData调用了setValue方法,最后是调到Super了,也就是LiveData中的setValue方法。

observe订阅源码分析

liveData.observe 方法 注册了一个观察者

//LiveData.java 类中
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    owner.getLifecycle().addObserver(wrapper);
}
  • 当前绑定的组件(activity或者fragment)状态为DESTROYED的时候, 则会忽视当前的订阅请求,也就是忽略owner的注册;

  • 如果需要与生命周期绑定, 则需要传入LifecycleOwner对象, 将我们的LiveData数据观测者(Observer)包装注册到生命周期的观测者中, 就是源码中创建wrapper对象过程;

  • 需要注意的问题是,不能添加具有不同生命周期的相同观察者,否则就会抛出IllegalArgumentException异常,但是owner可以add多个Observer;

  • 最后添加一个LifecycleObserver,它将在LifecycleOwner更改状态时得到通知,并做出及时的对应更新活动。

//LiveData的内部类
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        if (currentState == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            //调用父类的 activiStateChanged方法
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}


//父类 ObserverWrapper 中的方法
void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    mActive = newActive;
    changeActiveCounter(mActive ? 1 : -1);
    if (mActive) {
        //注意 这里传递了this 和 直接调用setValue 或者postValue 之后传递的null的区别
        dispatchingValue(this);
    }
}

LifecycleBoundObserver对象, 它继承于ObserverWrapper, 并最终实现了GenericLifecycleObserver接口,在LifecycleOwner生命收起发生变化的时候 就会调用onStateChanged方法,也间接印证,可以跟生命周期关联的,并且 不会发生内存泄漏,在处于DESTROYED 状态的时候就会自动移除观察者。

在最后LiveData 的observe方法中,最后调用 owner.getLifecycle().addObserver(wrapper); 给当前的Lifecycle增加一个LifecycleBoundObserver 的观察者, 这个最终会调用到LifeCycleRegistry中的addObserver方法,具体看LifeCycle的相关讲解分析

postValue 和 setValue分析

// LiveData.java
@MainThread
protected void setValue(T value) {
    //检测是否在主线程
    assertMainThread("setValue");
    //记录版本号,这个作用在ViewModel结合 LiveData使用的时候说其作用
    mVersion++;
    //赋值给mData
    mData = value;
    //分发对应的value改变
    dispatchingValue(null);
}

上面的代码就是主线程检查,赋值,分发的操作,主要的逻辑在dispatchingValue方法中

void dispatchingValue(@Nullable ObserverWrapper initiator) {
// mDispatchingValue的判断主要是为了解决并发调用dispatchingValue的情况
// 当对应数据的观察者在执行的过程中, 如有新的数据变更, 则不会再次通知到观察者。所以观察者内的执行不应进行耗时工作
    if (mDispatchingValue) {
        //标记当前分发无效
        mDispatchInvalidated = true;
        return;
    }
    //标记正在分发
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

方法解读:

  1. 上面的传入的initiator传入的是null ,需要注意 mDispatchingValue 和 mDispatchInvalidated的作用
  2. 遍历我们的observers 最终调用到considerNotify方法真正分发我们的数据

private void considerNotify(ObserverWrapper observer) {
    //检测是否处于活跃状态
    if (!observer.mActive) {
        return;
    }
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    //检测版本号
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

在considerNotify 中首先检查 当前的observer是否活着 这也应证了前面的优势,跟生命周期相关联,处于活跃的状态才更新数据。

mLastVersion和mVersion的作用

jetpack之LifeCycle 中我们其实在最后分析了Observer会走 backwardPass 和 forwardPass ,而LiveData 在执行addObserver的时候 也是会走这样一个逻辑。最终都会走到

void dispatchingValue(@Nullable ObserverWrapper initiator) 

这个方法中,我们调用setValue或者postValue的时候,这个ObserverWrapper会传入null,但是多次在执行生命周期的时候,会多次滴哦啊用dispatchValue方法,并传入ObserverWrapper参数,这样就有可能造成我们的观察者onChange会被调用多次,在setValue的时候每次mVersion都会++ ,但是生命周期调用的时候 不会++ ,就会造成我们的

if (observer.mLastVersion >= mVersion) {
        return;
    }

直接返回了,也就是 可以防止我们多次滴哦啊用onChange方法

LiveData的数据粘性

正是由于在添加Observer的时候,会根据生命周期 重走并且回调onChange方法。有点类似于EventBus的粘性广播的实现,如果是同一个LiveData,我们在setValue之后,在下一个Activity 中 再次使用同一个LiveData 注册观察者的时候,会得到最新的onChange的回调,有的时候,我们可能不希望这样,我们可以通过反射修改mLastVersion的值,屏蔽第一次的onChange回调,具体可以参考网上的文章

observe()和observerForever()

  • 一般我们使用 LiveData 的 observe(),当数据更新后,LiveData 会通知它的所有活跃的观察者。

  • 当然我们也可以使用 LiveData 的 observerForever() 方法进行订阅,区别是 observerForever() 不会受到 Activity 等组件的生命周期的影响,只要数据更新就会收到通知。

LiveData与MutableLiveData区别

LiveData与MutableLiveData的其实在概念上是一模一样的.唯一几个的区别如下:

1.MutableLiveData的父类是LiveData

2.LiveData在实体类里可以通知指定某个字段的数据更新.

3.MutableLiveData则是完全是整个实体类或者数据类型变化后才通知.不会细节到某个字段

class CustomLiveData:LiveData<CustomLiveData>() {

    private var fristName = "";
    private var lastName = "";

    public fun setFristName(name:String){
        fristName =  name
        postValue(this)
    }

    public fun setLastName(name:String){
        lastName =  name
        postValue(this)
    }
}

我们可以改变某个属性 就触发Observer的onChange的方法的回调

LiveData源码总结

  • LiveData的观察者可以联动生命周期, 也可以不联动。在联动生命周期时,会自动在 DESTROYED 的状态下移除 Observer ,取消订阅,所以不用担心内存泄露;

  • LiveData的观察者只能与一个LifecycleOwner绑定, 否则会抛出异常。而一个 owner 可以绑定多个 Observer 实例;

  • LiveData 跟 LifecycleOwner 绑定,能感知生命周期变化,并且只会在 LifecycleOwner 处于 Active 状态(STARTED/RESUMED)下通知数据改变;如果数据改变发生在非 active 状态,数据会变化,但是不发送通知,等 owner 回到 active 的状态下,再发送通知;

  • 使用observeForever()方法,会注意AlwaysActiveObserver对象,意味着给定的观察者将接收所有事件,并且永远不会被自动删除,不管在什么状态下都能接收到数据的更改通知

  • LiveData 利用版本管理、绑定 Lifecycle 确保了只会发送最新的数据给 active 状态下的 Observe

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值