Parece que se MutableLiveDatadiferencia LiveDatasolo por hacer públicos los métodos setValue()y postValue(), mientras que en LiveDataellos están protegidos.
¿Cuáles son algunas razones para crear una clase separada para este cambio y no simplemente definir esos métodos como públicos en LiveDatasí mismos?
En términos generales, ¿esta forma de herencia (el aumento de la visibilidad de ciertos métodos es el único cambio) una práctica bien conocida y cuáles son algunos escenarios en los que puede ser útil (asumiendo que tenemos acceso a todo el código)?
android
oop
android-architecture-components
android-livedata
Alexander Kulyakhtin
fuente
fuente

LiveDataes inmutable, ya que el cliente no puede cambiar el estado interno, por lo tanto, seguro para subprocesosRespuestas:
En LiveData - Android información sobre el desarrollador , se puede ver que para
LiveData,setValue()ypostValue()métodos no son públicos.Mientras que, en MutableLiveData - Documentación para desarrolladores de Android , puede ver que se
MutableLiveDataextiendeLiveDatainternamente y también los dos métodos mágicos deLiveDataestá disponible públicamente en esto y sonsetValue()&postValue().setValue(): establece el valor y envía el valor a todos los observadores activos, se debe llamar desde el hilo principal .postValue(): publicar una tarea en el hilo principal para anular el valor establecido porsetValue(), se debe llamar desde el hilo de fondo .Entonces,
LiveDataes inmutable .MutableLiveDataesLiveDataque es mutable y seguro para subprocesos .fuente
Este es el
MutableLiveData.javaarchivo completo :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); } }Entonces sí, la diferencia viene solo al hacer
postValueysetValuepublicar.Un caso de uso que puedo recordar de mi cabeza es el de la encapsulación usando Backing Property en Kotlin. Puede exponer
LiveDatasu Fragmento / Actividad (Controlador de IU) aunque pueda tenerMutableLiveDatamanipulación en suViewModelclase.class TempViewModel : ViewModel() { ... private val _count = MutableLiveData<Int>() val count: LiveData<Int> get() = _count public fun incrementCount() = _count.value?.plus(1) ... }De esta manera, su UI Controller solo podrá observar valores sin poder editarlos. Obviamente, su UI Controller puede editar valores usando métodos públicos de
TempViewModellikeincrementCount().Nota : para aclarar la confusión mutable / inmutable:
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 }fuente
_score?MutableLiveData se está extendiendo desde LiveData. Los métodos protegidos de LiveData solo pueden ser abordados por uno mismo o subclases. Entonces, en este caso, MutableLiveData, que es una subclase de LiveData, puede acceder a estos métodos protegidos.
Lo que le gustaría hacer es observar una instancia y ver si hay algún cambio. Pero al mismo tiempo, no desea que ningún "extraño" cambie la instancia que está observando. En cierto sentido, esto crea un problema, ya que le gustaría tener un objeto que sea y modificable, para actualizar cualquier estado nuevo, y no modificable, para asegurarse de que nadie que no deba pueda actualizar esta instancia. Estas dos características entran en conflicto entre sí, pero se pueden resolver creando una capa adicional.
Entonces, lo que hace es extender su clase, LiveData, con una clase que puede acceder a sus métodos. La subcapa, en este caso MutableLiveData, puede acceder a los métodos protegidos de su padre (/ super).
Ahora comienza a crear instancias y crea su instancia de observador de MutableLiveData. Al mismo tiempo, crea una instancia de LiveData que hace referencia a esta misma instancia. Debido a que MutableLiveData extiende LiveData, cualquier instancia de MutableLiveData es un objeto LiveData y, por lo tanto, una variable LiveData puede hacer referencia a ella.
Ahora el truco está casi hecho. Expone solo la instancia de LiveData, nadie puede usar sus métodos protegidos, ni puede convertirlo en su super (tal vez en tiempo de compilación, pero no se ejecutaría: error RunTime). Y mantiene la instancia de la subclase real privada, por lo que solo pueden cambiarla aquellos que son propietarios de la instancia, utilizando los métodos de la instancia.
//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(.....)Ahora la superclase notifica cuando se aplican cambios.
//change the instance by using the sub class _name.postValue(...) //or _name.setValue(...)Sí, es bastante conocido y esto descrito anteriormente es un escenario común. Eliminar el patrón de observador y hacerlo en una forma set / get sería igualmente beneficioso para él. Dependiendo de dónde lo implementes, al final no habrá reglas de oro.
fuente