Wygląda na to, że MutableLiveData
różni się od LiveData
tylko upublicznieniem metod setValue()
i postValue()
, podczas LiveData
gdy są one chronione.
Jakie są powody, dla których warto utworzyć osobną klasę dla tej zmiany, a nie po prostu zdefiniować te metody jako publiczne LiveData
same w sobie?
Ogólnie rzecz biorąc, czy taka forma dziedziczenia (zwiększenie widoczności niektórych metod jest jedyną zmianą) jest dobrze znaną praktyką i jakie scenariusze mogą się przydać (zakładając, że mamy dostęp do całego kodu)?
android
oop
android-architecture-components
android-livedata
Alexander Kulyakhtin
źródło
źródło
LiveData
jest niezmienny, ponieważ klient nie może zmienić stanu wewnętrznego, dlatego jest bezpiecznyOdpowiedzi:
W LiveData - Android dokumentacji dla programistów , można zobaczyć, że dla
LiveData
,setValue()
ipostValue()
metody nie są jawne.Podczas gdy w MutableLiveData - Android Developer Documentation widać, że
MutableLiveData
rozszerza sięLiveData
wewnętrznie, a także dwie magiczne metodyLiveData
są publicznie dostępne w tym i są tosetValue()
&postValue()
.setValue()
: ustaw wartość i wyślij wartość do wszystkich aktywnych obserwatorów, musi być wywołane z głównego wątku .postValue()
: wyślij zadanie do głównego wątku, aby nadpisać wartość ustawioną przezsetValue()
, musi być wywołane z wątku w tle .Więc
LiveData
jest niezmienna .MutableLiveData
toLiveData
co jest zmienny i bezpieczny wątku .źródło
To jest cały
MutableLiveData.java
plik: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); } }
Więc tak, różnica pojawia się tylko poprzez udostępnianie
postValue
isetValue
upublicznianie.Jednym z przypadków użycia, które mogę sobie przypomnieć, jest hermetyzacja przy użyciu właściwości Backing w Kotlinie. Możesz ujawnić
LiveData
swój fragment / aktywność (kontroler UI), nawet jeśli możeszMutableLiveData
manipulować w swojejViewModel
klasie.class TempViewModel : ViewModel() { ... private val _count = MutableLiveData<Int>() val count: LiveData<Int> get() = _count public fun incrementCount() = _count.value?.plus(1) ... }
W ten sposób kontroler interfejsu użytkownika będzie mógł obserwować tylko wartości bez możliwości ich edycji. Oczywiście kontroler interfejsu użytkownika może edytować wartości przy użyciu publicznych metod,
TempViewModel
takich jakincrementCount()
.Uwaga : aby wyjaśnić zmienne / niezmienne zamieszanie -
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 }
źródło
_score
?MutableLiveData rozszerza się z LiveData. Metody chronione LiveData mogą być adresowane tylko przez własne lub podklasy. W tym przypadku MutableLiveData będąca podklasą LiveData może uzyskać dostęp do tych chronionych metod.
To, co chciałbyś zrobić, to obserwować na instancji i zobaczyć, czy są jakieś zmiany. Ale jednocześnie nie chcesz, aby ktokolwiek z zewnątrz zmienił obserwowaną instancję. W pewnym sensie stwarza to problem, ponieważ chciałbyś mieć obiekt, który jest i można go zmieniać, aby aktualizować każdy nowy status i nie można go zmieniać, aby upewnić się, że nikt, kto nie powinien, nie może zaktualizować tej instancji. Te dwie funkcje są ze sobą sprzeczne, ale można je rozwiązać, tworząc dodatkową warstwę.
Więc to, co robisz, to rozszerzanie swojej klasy, LiveData, o klasę, która ma dostęp do jej metod. Warstwa podrzędna, w tym przypadku MutableLiveData, ma dostęp do chronionych metod swojego rodzica (/ super).
Teraz zaczynasz tworzyć instancje i tworzymy instancję obserwatora MutableLiveData. Jednocześnie tworzysz instancję LiveData odwołującą się do tej samej instancji. Ponieważ MutableLiveData rozszerza LiveData, każda instancja MutableLiveData jest obiektem LiveData i dlatego zmienna LiveData może się do niej odwoływać.
Teraz sztuczka jest prawie zakończona. Ujawniasz tylko instancję LiveData, nikt nie może używać jej chronionych metod, ani nie może przesyłać jej do super (być może w czasie kompilacji, ale nie działałaby: błąd RunTime). Zachowujesz prywatność rzeczywistej instancji podklasy, więc mogą ją zmienić tylko właściciele instancji, używając metod instancji.
//create instance of the sub class and keep this private private val _name: MutableLiveData<String> = MutableLiveData<String>() //create an instance of the super class referring to the same instance val name: LiveData<String> = _name
//assign observer to the super class, being unable to change it name.value.observe(.....)
Teraz superklasa powiadamia o zastosowaniu jakichkolwiek zmian.
//change the instance by using the sub class _name.postValue(...) //or _name.setValue(...)
Tak, jest to dość dobrze znane i ten opisany powyżej jest częstym scenariuszem. Usuń wzorzec obserwatora i po prostu utwórz go w formie set / get, przyniosłoby to równie duże korzyści. W zależności od tego, gdzie go wdrożysz, ostatecznie nie będzie żadnych złotych zasad.
źródło