web-dev-qa-db-ja.com

LiveDataのMutableLiveDataサブクラスが別にあるのはなぜですか?

MutableLiveDataLiveDataで保護されているのに対し、setValue()およびpostValue()メソッドをパブリックにすることでのみLiveDataと異なるようです。

LiveData自体で単純にこれらのメソッドをpublicとして定義するのではなく、この変更に対して別のクラスを作成する理由は何ですか?

一般的に言って、このような形式の継承(特定のメソッドの可視性を高めることが唯一の変更)はよく知られた慣行であり、それが役立つ可能性のあるシナリオは何ですか(すべてのコードにアクセスできると仮定して)?

51

LiveData-Android Developer Documentation では、LiveDataの場合、setValue()およびpostValue()メソッドがパブリックではないことがわかります。

一方、 MutableLiveData-Android Developer Documentation では、MutableLiveDataが内部的にLiveDataを拡張し、LiveDataの2つのマジックメソッドがpubliclyであることがわかります。 これで利用可能であり、setValue()postValue()です。

setValue():値を設定し、すべてのアクティブなオブザーバに値をディスパッチします。メインスレッドから呼び出す必要があります

postValue():メインスレッドにタスクをポストして、setValue()によって設定された値をオーバーライドします。バックグラウンドスレッドから呼び出す必要があります。

したがって、LiveDataimmutableです。 MutableLiveDataLiveDataで、mutablethread-safeです。

82
Sneh Pandya

これは、MutableLiveData.Javaファイル全体です。

package androidx.lifecycle;
/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
*/
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }
    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

そのため、違いはpostValuesetValueをパブリックにすることによってのみ生じます。

私が頭から思い出すことができるユースケースの1つは、Kotlinで Backing Property を使用したカプセル化です。 LiveDataクラスでの操作にMutableLiveDataを使用できる場合でも、ViewModelをフラグメント/アクティビティ(UIコントローラー)に公開できます。

    class TempViewModel : ViewModel() {
        ...
        private val _count = MutableLiveData<Int>()
        val count: LiveData<Int>
            get() = _count
        public fun incrementCount() = _score.value?.plus(1)
        ...
    }

これにより、UIコントローラーは、値を編集することなく、値を監視することしかできなくなります。明らかに、UIコントローラーはincrementCount()のようなTempViewModelのパブリックメソッドを使用して値を編集できます。

:可変/不変の混乱を明確にするために-

data class User(var name: String, var age: Int)

class DemoLiveData: LiveData<User>()

var demoLiveData: LiveData<User>? = DemoLiveData()

fun main() {
    demoLiveData?.value = User("Name", 23) // ERROR
    demoLiveData?.value?.name = "Name" // NO ERROR
    demoLiveData?.value?.age = 23  // NO ERROR
}
0