Похоже , что MutableLiveData
отличается от LiveData
только за счет изготовления setValue()
и postValue()
методы общественного, а в LiveData
их защите.
Каковы некоторые причины сделать отдельный класс для этого изменения, а не просто определять эти методы как общедоступные в самом LiveData
себе?
Вообще говоря, является ли такая форма наследования (увеличение видимости определенных методов единственным изменением) хорошо известной практикой и в каких сценариях она может быть полезна (при условии, что у нас есть доступ ко всему коду)?
android
oop
android-architecture-components
android-livedata
Александр Куляхтин
источник
источник
LiveData
является неизменным, так как клиент не может изменить внутреннее состояние, поэтому потокобезопасенОтветы:
В LiveData - Android документации разработчика , вы можете увидеть , что для
LiveData
,setValue()
иpostValue()
методы не являются публичными.В то время как, в MutableLiveData - Android документации разработчика , вы можете увидеть , что
MutableLiveData
расширяетLiveData
внутренне и также два магических методовLiveData
является публично доступны в этом и ониsetValue()
&postValue()
.setValue()
: установить значение и отправить значение всем активным наблюдателям, должен вызываться из основного потока .postValue()
: отправить задачу в основной поток, чтобы переопределить установленное значениеsetValue()
, необходимо вызывать из фонового потока .Таким образом,
LiveData
является непреложным .MutableLiveData
этоLiveData
что изменчиво и поточно- .источник
Это весь
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); } }
Так что да, разница заключается только в том, чтобы сделать
postValue
иsetValue
опубликовать.Один вариант использования, который я могу припомнить, - это инкапсуляция с использованием Backing Property в Kotlin. Вы можете подвергнуть
LiveData
свой фрагмент / действие (UI-контроллер), даже если вы можетеMutableLiveData
манипулировать в своемViewModel
классе.class TempViewModel : ViewModel() { ... private val _count = MutableLiveData<Int>() val count: LiveData<Int> get() = _count public fun incrementCount() = _count.value?.plus(1) ... }
Таким образом, ваш UI-контроллер сможет только наблюдать значения, не имея возможности редактировать их. Очевидно, ваш UI-контроллер может редактировать значения, используя общедоступные методы,
TempViewModel
подобныеincrementCount()
.Примечание : чтобы прояснить изменчивую / неизменную путаницу -
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 }
источник
_score
?MutableLiveData расширяется от LiveData. К защищенным методам LiveData можно обращаться только самими собой или подклассами. Таким образом, в этом случае MutableLiveData, являющийся подклассом LiveData, может получить доступ к этим защищенным методам.
Что вы хотите сделать, так это наблюдать за экземпляром и посмотреть, есть ли какие-либо изменения. Но в то же время вы не хотите, чтобы какие-либо «посторонние» изменили тот случай, за которым вы наблюдаете. В некотором смысле это создает проблему, так как вы хотели бы иметь объект, который можно изменять, обновлять любой новый статус, а не изменять, чтобы убедиться, что никто, кто не должен, не может обновлять этот экземпляр. Эти две функции конфликтуют друг с другом, но их можно решить, создав дополнительный слой.
Итак, что вы делаете, так это расширяете свой класс LiveData с помощью класса, который может получить доступ к его методам. Подуровень, в данном случае MutableLiveData, может получить доступ к защищенным методам своего родителя (/ super).
Теперь вы начинаете создавать экземпляры и создаете свой экземпляр наблюдателя MutableLiveData. В то же время вы создаете экземпляр LiveData, ссылающийся на этот же экземпляр. Поскольку MutableLiveData расширяет LiveData, любой экземпляр MutableLiveData является объектом LiveData и, следовательно, на него может ссылаться переменная LiveData.
Теперь фокус почти готов. Вы открываете только экземпляр LiveData, никто не может использовать его защищенные методы и не может преобразовать его в супер (возможно, во время компиляции, но он не будет работать: ошибка RunTime). И вы сохраняете фактический экземпляр подкласса закрытым, поэтому его могут изменить только те, кто владеет экземпляром, используя методы экземпляра.
//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(.....)
Теперь суперкласс уведомляет о применении любых изменений.
//change the instance by using the sub class _name.postValue(...) //or _name.setValue(...)
Да, это хорошо известно, и описанный выше сценарий является обычным. Удалите шаблон наблюдателя и просто сделайте его в форме set / get, и это принесет не меньшую пользу. В зависимости от того, где вы это реализуете, в конце концов не будет золотых правил.
источник