Parece que MutableLiveData
difere LiveData
apenas de tornar os métodos setValue()
e postValue()
públicos, enquanto em LiveData
eles são protegidos.
Quais são alguns motivos para criar uma classe separada para essa mudança e não simplesmente definir esses métodos como públicos em LiveData
si?
De modo geral, essa forma de herança (aumentar a visibilidade de certos métodos sendo a única mudança) é uma prática bem conhecida e quais são alguns cenários em que pode ser útil (assumindo que temos acesso a todo o código)?
android
oop
android-architecture-components
android-livedata
Alexander Kulyakhtin
fonte
fonte
LiveData
é imutável, pois o cliente não pode alterar o estado interno, portanto thread-safeRespostas:
Em LiveData - Android Developer Documentation , você pode ver que os métodos
LiveData
,setValue()
&postValue()
não são públicos.Considerando que, em MutableLiveData - Android Developer Documentation , você pode ver que,
MutableLiveData
se estendeLiveData
internamente e também os dois métodos mágicos deLiveData
está publicamente disponível neste e eles sãosetValue()
&postValue()
.setValue()
: define o valor e despacha o valor para todos os observadores ativos, deve ser chamado do thread principal .postValue()
: postar uma tarefa no thread principal para substituir o valor definido porsetValue()
, deve ser chamado a partir do thread em segundo plano .Portanto,
LiveData
é imutável .MutableLiveData
éLiveData
que é mutável e seguro para thread .fonte
Este é o
MutableLiveData.java
arquivo 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); } }
Então, sim, a diferença vem apenas tornando
postValue
esetValue
publicando.Um caso de uso que consigo lembrar é para o encapsulamento usando a propriedade Backing em Kotlin. Você pode expor
LiveData
ao seu Fragmento / Atividade (Controlador de IU), embora você possa terMutableLiveData
para manipulação em suaViewModel
classe.class TempViewModel : ViewModel() { ... private val _count = MutableLiveData<Int>() val count: LiveData<Int> get() = _count public fun incrementCount() = _count.value?.plus(1) ... }
Desta forma, o seu UI Controller só será capaz de observar os valores sem poder editá-los. Obviamente, seu UI Controller pode editar valores usando métodos públicos
TempViewModel
semelhantesincrementCount()
.Nota : Para esclarecer a confusão mutável / imutável -
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 }
fonte
_score
?MutableLiveData é uma extensão do LiveData. Os métodos protegidos do LiveData só podem ser endereçados por self ou subclasses. Portanto, neste caso, MutableLiveData, sendo uma subclasse de LiveData, pode acessar esses métodos protegidos.
O que você gostaria de fazer é observar uma instância e ver se há alguma mudança. Mas, ao mesmo tempo, você não quer que nenhum "estranho" altere a instância que você está observando. Em certo sentido, isso cria um problema, pois você gostaria de ter um objeto que é e pode ser alterado, para atualizar qualquer novo status, e não pode ser alterado, para garantir que ninguém que não deveria pode atualizar esta instância. Esses dois recursos são conflitantes, mas podem ser resolvidos criando uma camada extra.
Portanto, o que você faz é estender sua classe, LiveData, com uma classe que pode acessar seus métodos. A subcamada, neste caso MutableLiveData, é capaz de acessar os métodos protegidos de seu pai (/ super).
Agora você começa a criar instâncias e cria sua instância de observador de MutableLiveData. Ao mesmo tempo, você cria uma instância LiveData referindo-se a essa mesma instância. Como MutableLiveData estende LiveData, qualquer instância de MutableLiveData é um objeto LiveData e, portanto, pode ser referenciada por uma variável LiveData.
Agora o truque está quase pronto. Você expõe apenas a instância LiveData, ninguém pode usar seus métodos protegidos, nem pode lançá-lo em seu super (talvez em tempo de compilação, mas não seria executado: erro de tempo de execução). E você mantém a instância da subclasse real privada, de modo que ela só pode ser alterada por aqueles que possuem a instância, usando os métodos da instância.
//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(.....)
Agora a superclasse notifica quando qualquer alteração é aplicada.
//change the instance by using the sub class _name.postValue(...) //or _name.setValue(...)
Sim, é bastante conhecido e o descrito acima é um cenário comum. Remova o padrão do observador e apenas torná-lo em uma forma set / get teria o mesmo benefício com isso. Dependendo de onde você o implementa, não há regras de ouro no final.
fonte