Parece que se MutableLiveData
diferencia LiveData
solo por hacer públicos los métodos setValue()
y postValue()
, mientras que en LiveData
ellos 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 LiveData
sí 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
LiveData
es 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
MutableLiveData
extiendeLiveData
internamente y también los dos métodos mágicos deLiveData
está 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,
LiveData
es inmutable .MutableLiveData
esLiveData
que es mutable y seguro para subprocesos .fuente
Este es el
MutableLiveData.java
archivo 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
postValue
ysetValue
publicar.Un caso de uso que puedo recordar de mi cabeza es el de la encapsulación usando Backing Property en Kotlin. Puede exponer
LiveData
su Fragmento / Actividad (Controlador de IU) aunque pueda tenerMutableLiveData
manipulación en suViewModel
clase.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
TempViewModel
likeincrementCount()
.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