LiveData setValue和postValue的区别及详解

LiveData 相关学习资料

1. LiveData源码分析
2. LiveData扩展之MediatorLiveData
3. LiveData扩展之MediatorLiveData源码分析
4. LiveData扩展之Transformations


平时我们使用LiveData的时候,需要更新数据的时候,LiveData提供了两种更新数据的方式:

  • setValue(T value)
  • postValue(T value)

那么这两种方式有什么区别呢?

结论

setValue()只能在主线程中调用,postValue()可以在任何线程中调用。


源码分析

我们本着知其然知其所以然的态度来进行源码分析,赶项目的同学很忙的话就赶紧写代码去吧。

setValue()

我们先不急着看源码,先看官方如何介绍这个方法。

 /**
  * 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
  */
 @MainThread
 protected void setValue(T value)

上面的注释已经很清楚了:

这个方法必须在主线程中调用,如果你需要在后台线程中设置value,请移步 #postValue(Object)

更何况人家还用了一个 @MainThread的注解提醒你呢,接下来看源码:

protected void setValue(T value) {
        assertMainThread("setValue");	//1
        mVersion++;		//2
        mData = value;		//3
        dispatchingValue(null);		//4
    }
    
private static void assertMainThread(String methodName) {
        if (!ArchTaskExecutor.getInstance().isMainThread()) {
            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                    + " thread");
        }
    }
  1. 首先调用 assertMainThread() 方法来判断当前线程是否为主线程(这里他通过一个ArchTaskExecutor的单例类来实现),如果不是主线程,直接抛异常提醒程序员。
  2. 如果是在主线程中调用该方法,自加加一个version,来说明值发生了变化
  3. 再把新的值保存起来。
  4. 更新value(这个方法不能扯下去,扯下去就是LiveData的源码分析了)。

postValue

我们继续先看一下官方对postValue()的介绍:

 /**
     * Posts a task to a main thread to set the given value. So if you have a following code
     * executed in the main thread:
     * <pre class="prettyprint">
     * liveData.postValue("a");
     * liveData.setValue("b");
     * </pre>
     * The value "b" would be set at first and later the main thread would override it with
     * the value "a".
     * <p>
     * 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)

翻译过来就是:

通过任务(Runnable)的方式在主线程中更新数据。
如果同时调用 .postValue(“a”)和.setValue(“b”),一定是值b被值a覆盖。
如果多次调用 .postValue(),只有最后一个值能够被分发(onChanged()被调用)

再看详细的源码:

    protected void postValue(T value) {
        boolean postTask;		//1
        synchronized (mDataLock) {		//2
            postTask = mPendingData == NOT_SET;		//3
            mPendingData = value;		//3
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);	//4
    }
  1. 定义一个 postTask 的布尔值,判断是否要更新。
  2. 加个同步锁,因为可能存在多个子线程同时调用 .postValue() 的情况。
  3. 通过判断更新的值是否发生变化来对postTask赋值,并且将value赋值给 mPendingData(mPendingData == NOT_SET第一次一定是返回true,之后都是返回false,然后到这个值更新完毕之前的一瞬间会调用mPendingData=NOT_SET,这也是为什么多次调用 postValue()只有最后一个值才有效的原因)。
  4. 通过ArchTaskExecutor进行更新,通过方法及参数名字,我们可以猜测这一步干了什么事情:ArchTaskExecutor将一个Runnable对象往主线程里执行,那么mPostValueRunnable执行的环境一定是主线程,接下来我们再看看mPostValueRunnable究竟做了些什么。
private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

因为现在线程已经切换到主线程了,所以他直接就是调用 setValue()

最后

文中有几次出现了ArchTaskExecutor这个东西,这个类其实就是postValue切换至主线程更新的关键它具体的源码实现非常简单,直接是利用了Handler的机制。

  • 23
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值