LiveData的postValue丢值?setValue也丢值?

废话少说,少说废话。先上四个例子:

1、在onCreate中 for循环调用postValue

class MainActivity : AppCompatActivity() {

    private lateinit var activityMainBinding: ActivityMainBinding

    private val liveData = MutableLiveData<Int>()

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)

        setContentView(activityMainBinding.root)

        for (i in 0..2) {

           liveData.postValue(i)

            Log.d("MyMainActivity", "postValue: $i")

        }

        // 订阅观察者

        liveData.observe(this) {

            Log.d("MyMainActivity", "observer: $it")

        }

    }

}

输出打印:

2022-08-15 10:38:28.269 D/MyMainActivity: postValue: 0

2022-08-15 10:38:28.269 D/MyMainActivity: postValue: 1

2022-08-15 10:38:28.269 D/MyMainActivity: postValue: 2

2022-08-15 10:38:28.297 D/MyMainActivity: observer: 2

可以显而易见的看到postValue发送0,1,2数据后,但只接收到了最后一次发送的数值2.

2、在onCreate中 for循环调用setValue

class MainActivity : AppCompatActivity() {

    private lateinit var activityMainBinding: ActivityMainBinding

    private val liveData = MutableLiveData<Int>()

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)

        setContentView(activityMainBinding.root)

        for (i in 0..2) {

            liveData.value = i

            Log.d("MyMainActivity", "setValue: $i")

        }

        // 订阅观察者

        liveData.observe(this) {

            Log.d("MyMainActivity", "observer: $it")

        }

    }

}

输出:

2022-08-15 10:48:57.072  D/MyMainActivity: setValue: 0

2022-08-15 10:48:57.072  D/MyMainActivity: setValue: 1

2022-08-15 10:48:57.072  D/MyMainActivity: setValue: 2

2022-08-15 10:48:57.075  D/MyMainActivity: observer: 2

懵逼树下懵逼果,懵逼树下你和我,没错setValue也和postValue一样,只接收到了最后一次发送的数值2.

3、在onCreate中 点击按钮执行for循环调用postValue

class MainActivity : AppCompatActivity() {

    private lateinit var activityMainBinding: ActivityMainBinding

    private val liveData = MutableLiveData<Int>()

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)

        setContentView(activityMainBinding.root)

        activityMainBinding.btn.setOnClickListener {

            for (i in 0..2) {

                liveData.postValue(i)

                Log.d("MyMainActivity", "postValue: $i")

            }

        }

        // 订阅观察者

        liveData.observe(this) {

            Log.d("MyMainActivity", "observer: $it")

        }

    }

}

//输出打印:

2022-08-15 11:01:34.418 com.example.myapplication D/MyMainActivity: postValue: 0

2022-08-15 11:01:34.418 com.example.myapplication D/MyMainActivity: postValue: 1

2022-08-15 11:01:34.418 com.example.myapplication D/MyMainActivity: postValue: 2

2022-08-15 11:01:34.426 com.example.myapplication D/MyMainActivity: observer: 2

这个例子的结果同第一个一样,postValue连续发送数据,最后只接收到最后的数据。

4、在onCreate中 点击按钮执行for循环调用setValue


class MainActivity : AppCompatActivity() {

    private lateinit var activityMainBinding: ActivityMainBinding

    private val liveData = MutableLiveData<Int>()

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)

        setContentView(activityMainBinding.root)

        activityMainBinding.btn.setOnClickListener {

            for (i in 0..2) {

                liveData.value = i

                Log.d("MyMainActivity", "setValue: $i")

            }

        }

        // 订阅观察者

        liveData.observe(this, object : androidx.lifecycle.Observer<Int> {

            override fun onChanged(it: Int?) {

                Log.d("MyMainActivity", "observer: $it")

            }

        })

        //lambda写法(后面都用这种写法)

    //    liveData.observe(this) {

    //        Log.d("MyMainActivity", "observer: $it")

    //    }


    }

}

输出:

2022-08-15 11:02:29.333 D/MyMainActivity: observer: 0

2022-08-15 11:02:29.333 D/MyMainActivity: setValue: 0

2022-08-15 11:02:29.333 D/MyMainActivity: observer: 1

2022-08-15 11:02:29.333 D/MyMainActivity: setValue: 1

2022-08-15 11:02:29.333 D/MyMainActivity: observer: 2

2022-08-15 11:02:29.333 D/MyMainActivity: setValue: 2

守得云开见月明,终于见到想要的结果了。setValue连续发送数据,每次数据都能被接收到,而不是丢失数据,只能接收到最后一次发送的数据。

先分析下setValue的情况,再来捋postValue的。


 /**

     * Sets the value. If there are active observers, the value will be dispatched to them.

     * <p>

     * This method must be called from the main thread. If you need set a value from a background

     * thread, you can use {@link #postValue(Object)}

     *

     * @param value The new value

     * 以上大致意思就是:设置value值,如果是活跃的observers,则会把值分发给它们

     * 这个函数必须在主线程调用,如果要在子线程调用就用postValue

     */

    @MainThread

    protected void setValue(T value) {

        assertMainThread("setValue");//判断setValue方法是否在主线程调用,

        mVersion++;

        mData = value;//将value的值赋值给LiveData的成员属性 mData,给Observer的onChange回调

        dispatchingValue(null); 分发 value 这个传入参数的值为null

    }

   以上代码可以得出结论,setValue必须在主线程执行,assertMainThread方法会判断setValue是否在主线程。其次value的值赋值给LiveData的成员属性 mData(mData给Observer的onChange回调),而dispatchingValue方法就是分发你value的,下面看下这个方法里面干了啥。

     @SuppressWarnings("WeakerAccess") /* synthetic access */

    void dispatchingValue(@Nullable ObserverWrapper initiator) {

        if (mDispatchingValue) {//默认是false 所以条件不成立 return 语句不会执行

            mDispatchInvalidated = true;

            return;

        }

        mDispatchingValue = true;

        do {

            mDispatchInvalidated = false;

            if (initiator != null) {// initiator 传入的值为null 所以会走到下面else判断条件里

                considerNotify(initiator);

                initiator = null;

            } else {

                // 遍历mObservers

                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =

                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {                     
                    considerNotify(iterator.next().getValue());

                    if (mDispatchInvalidated) {

                        break;

                    }

                }

            }

        } while (mDispatchInvalidated);

        mDispatchingValue = false;

    }
  

      首先第一个判断条件mDispatchingValue默认是false 所以条件不成立 return 语句不会执行。

而setValue 我们的 dispatchingValue(null)传入是null,所以代码会走到遍历mObservers的else分支里,遍历出的数据传入considerNotify里,那直接看下considerNotify里又干了啥。

  @SuppressWarnings("unchecked")

    private void considerNotify(ObserverWrapper observer) {

        if (!observer.mActive)  // 判断 observer 是否在活跃状态

            return;

        }

        /*检查最新状态b4调度。也许它改变了状态,但我们还没有得到事件。

         *我们还是先检查观察者。激活以保持它作为事件的入口。因此,即使

         *观察者移动到活动状态,如果我们没有收到该事件,我们最好不要

          *notify用于更可预测的通知命令。

        */

        if (!observer.shouldBeActive()) {// 判断 observer 是否在活跃状态

            observer.activeStateChanged(false);

            return;

        }

        if (observer.mLastVersion >= mVersion) {// 校验 Observer 的版本号是否小于 LiveData 的版本号

            return;

        }

        observer.mLastVersion = mVersion;

        observer.mObserver.onChanged((T) mData);// 将mData传递给了 Observer 的 onChanged 方法

    }

   

   三个if判断条件,如果都不成立,会走到下面onChaged回调里,下发数据。OK,那么可以大胆猜测,setValue数据会丢失,就是这三个if条件为true,导致数据未走到onChanged回调里。

   第一个判断条件 if (!observer.mActive)和第二个判断条件 if (!observer.shouldBeActive()) 都是ObserverWrapper 的得属性或者方法调用出来的,所以看下ObserverWrapper里有什么名堂。

private abstract class ObserverWrapper {

        final Observer<? super T> mObserver;

        boolean mActive;

        int mLastVersion = START_VERSION;



        ObserverWrapper(Observer<? super T> observer) {

            mObserver = observer;

        }



        abstract boolean shouldBeActive();



        boolean isAttachedTo(LifecycleOwner owner) {

            return false;

        }



        void detachObserver() {

        }

         //通过这个方法修改mActive的值

        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);

            }

        }

    }

可以看到mActive的值在activeStateChanged方法里被重新赋值了,所以看下哪里调用了该方法并传入newActive参数就晓得了。先了解下 LiveData 的 observe 方法:

@MainThread

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {

    assertMainThread("observe");

    if (owner.getLifecycle().getCurrentState() == DESTROYED) {

        // ignore

        return;

    }

    // 创建了 LifecycleBoundObserver 对象,传入我们的 Observer 对象到构造函数

    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;

    }

    // 将 LifecycleBoundObserver 对象添加观察 Lifecycle 生命周期

    owner.getLifecycle().addObserver(wrapper);

}

LifecycleBoundObserver 继承了 ObserverWrapper,并实现了 LifecycleEventObserver 接口用于观察生命周期事件 

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() {

        // 返回当前生命周期至少是 STARTED 状态才为 true,否则 false

        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;

            activeStateChanged(shouldBeActive());

            currentState = mOwner.getLifecycle().getCurrentState();

        }

    }


    @Override

    boolean isAttachedTo(LifecycleOwner owner) {

        return mOwner == owner;

    }


    @Override

    void detachObserver() {

        mOwner.getLifecycle().removeObserver(this);

    }

}

以上代码需要注意:shouldBeActive()方法和onStateChanged方法里的 activeStateChanged();

 activeStateChanged方法中可以看到调用了父类 ObserverWrapper 的 activeStateChanged 对象,但是传入的值是 shouldBeActive 方法的返回值,shouldBeActive 方法也是父类 ObserverWrapper 的方法,但是是抽象方法,shouldBeActive 在 LifecycleBoundObserver 中实现在上面。

因此  上面提到过的void considerNotify(ObserverWrapper observer)方法中2个判断条件已经找到

关键是看mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED)这个状态的判断。

  /**

         * Compares if this State is greater or equal to the given {@code state}.

         * @param state State to compare with

         * @return true if this State is greater or equal to the given {@code state}

         *翻译:比较这个状态是否大于或等于给定的{@code状态}。

         */

        public boolean isAtLeast(@NonNull State state) {

            return compareTo(state) >= 0;

        }

       

        传入的值为是一个枚举类型 STARTED,看下这个STARTED官网描述:           

 public enum State {

                ...

       /**

         * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state

         * is reached in two cases:

         * <ul>

         *     <li>after {@link android.app.Activity#onStart() onStart} call;

         *     <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.

         * </ul>

         翻译:android.app.Activity#onStart() onStar之后调用,android.app.Activity#onPause() onPause之前调用

         */

        STARTED,

        ...

            }

        ok ,那就说明只能在activity生命周期中 onStart和onPause之间调用,observer.shouldBeActive为true,observer.mActive也为true,才能走onChangde回调。  

            所以开头第二个和第四个现象就能解释了。第四个是因为 LiveData 的观察生命周期的特性,

            只有在页面活跃状态下才可以分发值,当可以点击按钮时候,当前Activity 的生命周期已经走过了 OnStart、onResume,

            满足当前生命周期至少是 STARTED 的状态,setValue 到最终分发值一路畅通无阻,所以 for 循环中,每 set Value 一次,最终都会调用 Observer 的 onChanged 方法。        

        对于第二个的现象,为什么在 onCreate 方法中循环调用 setValue 最终只通知了最后一个值呢?

        因为在 onCreate 方法中调用的 setValue,observer.mActive 一定为 false, 而且最终 for 循环走完,LiveData 的 mVersion 为 2,mData 为 2,这解释了最终 LiveData 的 mData 值为 2,

        Observer 对象的 mLastVersion 也不会被赋值,始终为 -1,那么considerNotify(observer) 最后一个判断条件也找到了。     

        LiveData 调用 observe 时,observe 方法内,会将 Observer 对象包装为可感知生命周期的 LifecycleBoundObserver 对象,LifecycleOwner获取生命周期的状态,在 onStateChanged 中接受生命周期事件的改变,

        方法内调用 LifecycleBoundObserver 的父类的 activeStateChanged 方法,传入的是 shouldBeActive() 方法的返回值,而 shouldBeActive() 方法判断  mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED),

        也就是 调用 onStart 后;就在 onPause 调用之前 是返回 true。            

 void activeStateChanged(boolean newActive) {

    // newActive 就是shouldBeActive()的返回值为true ,而mActive一直为false,所以条件不成立

    if (newActive == mActive) {

        return;

    }


    mActive = newActive;//将newActive=true 赋值给mActive ,

    changeActiveCounter(mActive ? 1 : -1);

    // 此时mActive为true  条件满足,调用 dispatchingValue

    if (mActive) {

        dispatchingValue(this);

    }

}

这次dispatchingValue(this)传入不为null了,会去执行considerNotify(initiator)代码


 @SuppressWarnings("WeakerAccess") /* synthetic access */

    void dispatchingValue(@Nullable ObserverWrapper initiator) {

        if (mDispatchingValue) {

            mDispatchInvalidated = true;

            return;

        }

        mDispatchingValue = true;

        do {

            mDispatchInvalidated = false;

            if (initiator != null) {//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;

    }

  @SuppressWarnings("unchecked")

    private void considerNotify(ObserverWrapper observer) {

        if (!observer.mActive) {//mActive为true 条件不成立

            return;

        }

        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.

        //

        // we still first check observer.active to keep it as the entrance for events. So even if

        // the observer moved to an active state, if we've not received that event, we better not

        // notify for a more predictable notification order.

        if (!observer.shouldBeActive()) {//shouldBeActive 条件不成立

            observer.activeStateChanged(false);

            return;

        }

        if (observer.mLastVersion >= mVersion) {//mLastVersion 值为 -1, 而 mVersion 值为 2,条件不成立

            return;

        }

        observer.mLastVersion = mVersion;

        observer.mObserver.onChanged((T) mData);//onChanged 传入了最新的值为2

    }

    解释在代码注释中说明白了,废话不多说,少说废话。再来看下postValue的情况,先看下postValue的源码注释。

     /**

     * If you called this method multiple times before a main thread executed a posted task, only

     * the last value would be dispatched.

     *翻译:如果在主线程执行一个已发布的任务之前多次调用此方法,则只会分派最后一个值。

     * @param value The new value

     */

    protected void postValue(T value) {

    boolean postTask;

    // 同步代码块 使用 mDataLock 对象当锁

    synchronized (mDataLock) {

        // 如果 mPendingData 等于 NOT_SET 值 postTask 才为 true

        postTask = mPendingData == NOT_SET;

        // postValue 传的值赋值给成员属性 mPendingData

        mPendingData = value;

    }

    // 若 postTask 为 false 则 return

    if (!postTask) {

        return;

    }

    // 发送一个消息到主线程 handler,

    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

}

注释说的很明白:如果在主线程执行一个已发布的任务之前多次调用此方法,则只会分派最后一个值。但还是得捋捋为啥。

postValue内部维护了一个boolean类型的postTask,利用synchronized对一个objec对象 mDataLock加了锁,并且内部有一个全局变量mPendingData,这是问题的关键。每次postValue会将新的值赋给mPendingData,

然后会在一个Runnable中进行值的分发,且使用ArchTaskExecutor将该Runnable的任务发布到主线程中

• for 循环第一次调用 postValue 值 0 时,LiveData 的 mPendingData = NOT_SET, postTask = mPendingData == NOT_SET 为 true,mPendingData 赋值为 value 0,下面判断条件 !postTask 为 false,往消息队列插入一条消息 Runable 对象为 mPostValueRunnable。

• for 循环第二次调用 postValue 值 1 时,LiveData 的 mPendingData = 0,postTask = mPendingData == NOT_SET 为 false,mPendingData 赋值为 value 1,下面判断条件 !postTask 为 true,直接 return 不会再向主线程发消息咯。

• for 循环第三次调用 postValue 值 2 时,LiveData 的 mPendingData = 1,postTask = mPendingData == NOT_SET 为 false,mPendingData 赋值为 value 2,下面判断条件 !postTask 为 true,直接 return 也不会再向主线程发消息。

// 主线程消息队列执行到 Message 时调用的 runnable

private final Runnable mPostValueRunnable = new Runnable() {

    @SuppressWarnings("unchecked")

    @Override

    public void run() {

        Object newValue;//newValue =2

        // 同步锁

        synchronized (mDataLock) {

            // 将 mPendingData 赋值给 newValue 对象

            newValue = mPendingData;//mPendingData =2

            // 将 mPendingData 对象值重置为 NOT_SET

            mPendingData = NOT_SET;

        }

        // 这里又调用了 setValue,之后就跟 LiveData.setValue 流程一样了。

        setValue((T) newValue);//newValue =2

    }

};

    为什么第一次postValue的值没有更新?

    postValue方法内部其实是将值得回调逻辑放到了Runnable中,再post给Handler,利用Handler在主线程中更新,因此从postValue到执行Runnable,中间是存在时间差的,同时也说明 postValue是可以在子线程中发送数据的,在执行Runnable之前,因为是连续调用的postValue,

    第一次mPendingData的值被第二次调用时的值覆盖掉了,最后执行Runnable时,mPendingData的值只能是最新的那个,也就是带着第二次的值触发onChange回调给UI。-

    参考:https://mp.weixin.qq.com/s/cntZnRvYFglJhOuaQ0QCIw

    参考:https://mp.weixin.qq.com/s/Ul4m2bCHELBk8YoUP2vewQ

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chen_ShengJie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值