前言

在我的上一篇为什么Google要将LiveData设计成粘性的文章中,有一位爱思考的小伙伴留下了这么一个评论。

为什么LiveData的观察者必须处于主线程中

在看到这个评论后,我产生了两个疑问?

  1. Livandroid手机eData的观察者对象必须得处于主线程中吗?
  2. 究竟是什么原因让Google这么设计,正是这位小伙伴所述的原因吗?

由此有了这篇文章,再次感谢这位小伙伴的留言探讨。

观察者对象必须得处于主线程中安全期计算器吗?

googleplay说答案:

是的,Li安全模式veData多线程并发中线程的状态的观察者对象必多线程是什么意思须处于主线程中。

找到这个答案的方法也很简单,我们直接查看LiveDataandroid是什么系统源码中的多线程面试题册观察者方法即可。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    ...省略代码...
}
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    ...省略代码...
}
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ...省略代码...
}
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
    assertMainThread("removeObservers");
    ...省略代码...
}

不管是注册观察者方法还是注销观察者方法中,都使用了assertMainThread()方法来保证方法处于主线程中,如果方法处于子线程中就会直接抛出异常。

OK,知道了答案,接多线程面试题着就是下一个为什么了。

为什么观察者必须处于主线程中

这里我们采用反证法,假设我们的观察者对象是可以处于子线程中的,那会发生什么?

假设现在我们有android手机多个子线程,且它们引用了同一个Observ多线程的应用场景er,这时LiveData持有的数源码中的图片据发生了更新,需要将该最新数据通知到所有处于活跃状态的观察者对象。

如果你熟悉LiveData安全源码,那么你肯定知道,是否通知观察者对象的判断依据正是通过obgoogle商店server.mLastVersionLiveData.mVersion版本对比。

private void considerNotify(ObserverWrapper observer) {
    ...省略代码...
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

那此时,如果我们的观察者对象是处于多线程并发环境下,也就是considerNotify源码方法是处于并发环境下,此刻源码编程器无法保证线程安全的。从而mLastVersion无法保证内存及时可见性,从而造成与LiveDatamV多线程的实现方式ersion对比出现问题,结果就会造成android下载某些子线程中的观察者无法接收到数据更新的通知。

所以说,我们应该在保证线程google谷歌搜索主页安全下进行observer.mLastVersionLiveData.mVersion的版本比对工作。

那如何来保证线程Google安全呢?

那Google是怎么保证线程安全呢?

从代码中,我们可以发现considerNotify方法是一个私有函数,所以我们从considerNotify方法开始往上推,可以发现considerNotify方法只是被dispatchingValue方法所调用,那我们就需要具体看googleplay看哪里调用了dispatchingValue方法。

查看LiveData源码,我们可以发现只在两个地方调用到,分别是:

  1. setValue()方法中被调用。
  2. ObserverWrapper.activeStateChanged()方法中被调用。
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}
private abstract class ObserverWrapper {
    ......
    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        // immediately set active state, so we'd never dispatch anything to inactive
        // owner
        mActive = newActive;
        changeActiveCounter(mActive ? 1 : -1);
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

我们知道LiveData会在数据发生更改去通知所有处于活跃状态的观察者对象以及在某个观察者对象生命周期状态发生更改时去通知它,而这就体现在这两个方法中。

首先,setValue()方法相信大家都很熟悉,我们必须在主线程中进行调用,否则会抛出异常。在代码中体现出来的,正是通过assertMainThread("setValue");来保证方法处于主线程中。

那Google是如何保googleplayObserverWrapper.active安全工程师StateChange安全生产法d()方法中的dispatchingValue方法是处于主线程的呢?

答:直接让整个ObserverWrapper处于主线程中,也就是直接让我们的观察者对象处于主线程中,安全从而来保证线程安全。

为什么不用Synchronized + Volatile来保证线程安全呢?

不知你有没有同样的疑问:
为什么不用Synchronized+Volatile关键字来保证该方法线程安全呢?就像postValue()方法那样。那这样我们就可以在子线程中注册观察者对象了。

从实际业务出发来思考:
在实际业务开发中,我们基本上都是google服务框架拿到LiveData中的最新数据,然后更新UI。而这使用场景也决定我们的观察者对象只需处于主线程中即可,不需要googleplay处于子线程中。这样一来,Google直接规定观察者对象必须处于主线程中,就可以很好的保证线程安全。相对比采用Synchronized+Vola源码之家tile关键字来保证线程安安全教育平台登录入口全,更加的简单高效。

当然这只是我的一个观点,欢迎大家安全教育平台登录留言与我一同探讨。你们有遇到过需要在子线程中注册观察者的使用安全教育平台作业登录场景吗?

总结

本文是基于小伙伴的留言来展开思考,通过本文,我们知道LiveData的观察者对android什么意思象必须得处于主线程中,因为我们google商店应该在保证线程安全下进行observer.mLastVersionLiveData.mVersion的版本比对工作。相对比postValue()方法采用Synchronized+Volatile关键字来保证线程安全,这里Google直接通过规定观察者对象必须处于主线程中多线程编程来保证线程安全,十分简单高效。

到此本篇文章就结束啦,如果你有任何疑问或者不同的想法,欢迎在评论区留言与我一起探讨。

其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。

另外,如果你觉得文章不错,对你有所帮助,请帮我点个赞,就当鼓励,谢谢

相关联文章推荐阅读:

  • 为什么Google要将LiveData设计成android是什么系统粘性的
  • Android程序员重头学Synchronized
  • Androigoogle服务框架d程序员重头学Volatile