LiveDataのpostValueは全て流れてくるとは限らない

More than 1 year has passed since last update.


結論


  • LiveData.postValueを短い間に複数回コールすると最後の値しかObseverに流れてこないことがある


背景

RxJavaのSubjectの代替としてMutableLiveData(postValueとsetValueがpublicになっている)を使っている部分があり、短い間に2回コールされたとき、全ての値が流れて欲しかったが何故か1回しか叩かれていなかった。

どこに原因があるか調査したところ、どうもpostValueメソッドの仕様(LiveDataクラス全体の仕様?)的に短い間に複数回コールされた場合は、最後にpostValueした値のみをpostするようになっていた。


実装詳細

LiveDataのpostValueのコードは以下のようになっています(v1.0.0)

protected void postValue(T value) {

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

postValueメソッドでは


  1. 1. mPendingDataフィールドにObserverに渡すデータをセットする

  2. メインスレッドでmPostValueRunnableを実行する
    (ただしmPendingDataにまだ以前のデータが残っていたら、以前のデータを更新する)

といったことをやっています。

このコードを見て分かる通り、前にセットしたmPendingDataがObserverに渡される前に、新しい値で上書きされる可能性があることが分かります。

よって、短い間に複数回のpostValueをコールすると最後の値のみしかObserverに流れてこない可能性があります。


まとめ


  • RxJavaのSubjectのように、全ての値を流す動作を意図しているとハマる

  • そもそもLiveDataは最新のViewの状態を保持する用途だと思うので、短い間に複数回コールされたら、最後の値のみを流すのは正しい。LiveDataは悪くない。悪いのは俺。