面试官揪着不放,非搞个 LiveData postValue 死亡四连问?

很多面试官喜欢会就一个问题不断深入追问。

例如一个小小的 LiveData 的 postValue,就可能会问出一连串问题:

面试官揪着不放,非搞个 LiveData postValue 死亡四连问?

postValue 与 setValue

postValue 与 setValue 一样都是用来更新 LiveData 数据的方法:

  • setValue 只能在主线程调用,同步更新数据
  • postValue 可在后台线程调用,其内部会切换到主线程调用 setValue
liveData.postValue("a"); liveData.setValue("b"); 

上面代码,a 在 b 之后才被更新。

postValue 收不到通知

postValue 使用不当,可能发生接收到数据变更的通知:

If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.

如上,源码的注释中明确记载了,当连续调用 postValue 时,有可能只会收到最后一次数据更新通知。

梳理源码可以了解其中原由:

protected void postValue(T value) {     boolean postTask;     synchronized (mDataLock) {         postTask = mPendingData == NOT_SET;         mPendingData = value;     }     if (!postTask) {         return;     }     ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } 

mPendingData 被成功赋值 value 后,post 了一个 Runnable

mPostValueRunnable 的实现如下:

private final Runnable mPostValueRunnable = new Runnable() {     @SuppressWarnings("unchecked")     @Override     public void run() {         Object newValue;         synchronized (mDataLock) {             newValue = mPendingData;             mPendingData = NOT_SET;         }         setValue((T) newValue);     } }; 
  • postValue 将数据存入 mPendingDatamPostValueRunnable 在UI线程消费mPendingData

  • 在 Runnable 中 mPendingData 值还没有被消费之前,即使连续 postValue , 也不会 post 新的 Runnable

  • mPendingData 的生产 (赋值) 和消费(赋 NOT_SET) 需要加锁

这也就是当连续 postValue 时只会收到最后一次通知的原因。

源码梳理过了,但是为什么要这样设计呢?

为什么 Runnable 只 post 一次?

当 mPenddingData 中有数据不断更新时,为什么 Runnable 不是每次都 post,而是等待到最后只 post 一次?

一种理解是为了兼顾性能,UI只需显示最终状态即可,省略中间态造成的频发刷新。这或许是设计目的之一,但是一个更为合理的解释是:即使 post 多次也没有意义,所以只 post 一次即可

我们知道,对于 setValue 来说,连续调用多次,数据会依次更新:

如下,订阅方一次收到 a b 的通知

liveData.setValue("a"); liveData.setValue("b"); 

通过源码可知,dispatchingValue() 中同步调用 Observer#onChanged(),依次通知订阅方:

//setValue源码  @MainThread protected void setValue(T value) {     assertMainThread("setValue");     mVersion++;     mData = value;     dispatchingValue(null); } 

但对于 postValue,如果当 value 变化时,我们立即post,而不进行阻塞

protected void postValue(T value) {     mPendingData = value;     ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }  private final Runnable mPostValueRunnable = new Runnable() {     public void run() {         setValue((T) mPendingData);     } }; 
liveData.postValue("a") liveData.postValue("b") 

由于线程切换的开销,连续调用 postValue,收到通知只能是b、b,无法收到a。

因此,post 多次已无意义,一次即可。

为什么要加读写锁?

前面已经知道,是否 post 取决于对 mPendingData 的判断(是否为 NOT_SET)。因为要在多线程环境中访问 mPendingData ,不加读写锁无法保证其线程安全。

protected void postValue(T value) {     boolean postTask = mPendingData == NOT_SET; // --1     mPendingData = value; // --2     if (!postTask) {         return;     }     ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }  private final Runnable mPostValueRunnable = new Runnable() {     public void run() {         Object newValue = mPendingData;         mPendingData = NOT_SET; // --3         setValue((T) newValue);     } }; 

如上,如果在 1 和 2 之间,执行了 3,则 2 中设置的值将无法得到更新

使用RxJava替换LiveData

如何避免在多线程环境下不漏掉任何一个通知? 比较好的思路是借助 RxJava 这样的流式框架,任何数据更新都以数据流的形式发射出来,这样就不会丢失了。

fun <T> Observable<T>.toLiveData(): LiveData<T> = RxLiveData(this)  class RxLiveData<T>(     private val observable: Observable<T> ) : LiveData<T>() {     private var disposable: Disposable? = null      override fun onActive() {         disposable = observable             .observeOn(AndroidSchedulers.mainThread())             .subscribe({                 setValue(it)             }, {                 setValue(null)             })     }      override fun onInactive() {         disposable?.dispose()     } } 

最后

想要保证事件在线程切换过程中的顺序性和完整性,需要使用RxJava这样的流式框架

有时候面试官会使用追问的形式来挖掘候选人的技术深度,所以大家在准备面试时要多问自己几个问什么,知其然并知其所以然。

最后,在这里我给大家提供一份自己收录整理上述Android技术体系图相关的高级进阶必刷文档(已整理成PDF模板),包含了Android 基础,进阶,架构、 Kotlin,Flutter,NDK,小程序,面试题,面经,都有收录,供君一览。

面试官揪着不放,非搞个 LiveData postValue 死亡四连问? 面试官揪着不放,非搞个 LiveData postValue 死亡四连问?

还有 高级架构技术进阶思维图帮助大家学习提升进阶,也节省大家在网上搜索的时间来学习,也希望大家可以和身边好友一起学习。最后祝愿大家都能有个光明的未来。

有需要的朋友可以" 查阅下方的Github项目 "即可;

Github地址:【https://github.com/733gh/xiongfan2.0/tree/main】

面试官揪着不放,非搞个 LiveData postValue 死亡四连问?

版权声明:玥玥 发表于 2021-06-11 11:44:17。
转载请注明:面试官揪着不放,非搞个 LiveData postValue 死亡四连问? | 女黑客导航