Il semble que cela MutableLiveData
diffère du LiveData
seul fait de rendre publiques les méthodes setValue()
et postValue()
, alors LiveData
qu'elles sont protégées.
Quelles sont les raisons de créer une classe distincte pour ce changement et de ne pas simplement définir ces méthodes comme publiques en LiveData
soi?
D'une manière générale, une telle forme d'héritage (l'augmentation de la visibilité de certaines méthodes étant le seul changement) est-elle une pratique bien connue et quels sont certains scénarios où elle peut être utile (en supposant que nous ayons accès à tout le code)?
android
oop
android-architecture-components
android-livedata
Alexandre Kulyakhtin
la source
la source
LiveData
est immuable, puisque le client ne peut pas changer l'état interne, donc thread-safeRéponses:
Dans LiveData - Documentation pour les développeurs Android , vous pouvez voir que pour
LiveData
, les méthodessetValue()
&postValue()
ne sont pas publiques.Alors que, dans MutableLiveData - Documentation pour les développeurs Android , vous pouvez voir que,
MutableLiveData
s'étend enLiveData
interne et que les deux méthodes magiques deLiveData
sont disponibles publiquement dans ce document et qu'elles sontsetValue()
&postValue()
.setValue()
: définir la valeur et distribuer la valeur à tous les observateurs actifs, doit être appelée à partir du thread principal .postValue()
: publier une tâche sur le thread principal pour remplacer la valeur définie parsetValue()
, doit être appelée à partir du thread d'arrière-plan .Donc,
LiveData
c'est immuable .MutableLiveData
estLiveData
qui est mutable et thread-safe .la source
Voici le
MutableLiveData.java
fichier complet :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); } }
Alors oui, la différence ne vient que du rendu
postValue
et dusetValue
public.Un cas d'utilisation dont je peux me souvenir de ma tête est l'encapsulation à l'aide de Backing Property dans Kotlin. Vous pouvez exposer
LiveData
à votre fragment / activité (contrôleur d'interface utilisateur) même si vous pouvez avoirMutableLiveData
pour manipulation dans votreViewModel
classe.class TempViewModel : ViewModel() { ... private val _count = MutableLiveData<Int>() val count: LiveData<Int> get() = _count public fun incrementCount() = _count.value?.plus(1) ... }
De cette façon, votre contrôleur d'interface utilisateur ne pourra observer que les valeurs sans pouvoir les modifier. De toute évidence, votre contrôleur d'interface utilisateur peut modifier les valeurs à l'aide de méthodes publiques
TempViewModel
similairesincrementCount()
.Remarque : pour clarifier la confusion mutable / immuable -
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 }
la source
_score
?MutableLiveData est une extension de LiveData. Les méthodes protégées de LiveData ne peuvent être adressées que par soi-même ou par des sous-classes. Donc, dans ce cas, MutableLiveData étant une sous-classe de LiveData peut accéder à ces méthodes protégées.
Ce que vous aimeriez faire, c'est observer sur une instance et voir s'il y a des changements. Mais en même temps, vous ne voulez pas que des "étrangers" modifient cette instance que vous observez. Dans un sens, cela crée un problème, car vous aimeriez avoir un objet qui soit et modifiable, pour mettre à jour tout nouveau statut, et non modifiable, pour vous assurer que personne qui ne devrait pas peut mettre à jour cette instance. Ces deux fonctionnalités sont en conflit l'une avec l'autre, mais peuvent être résolues en créant une couche supplémentaire.
Donc, ce que vous faites est d'étendre votre classe, LiveData, avec une classe qui peut accéder à ses méthodes. La sous-couche, dans ce cas MutableLiveData, est capable d'accéder aux méthodes protégées de son parent (/ super).
Vous commencez maintenant à créer des instances et créez votre instance d'observateur de MutableLiveData. En même temps, vous créez une instance LiveData faisant référence à cette même instance. Comme MutableLiveData étend LiveData, toute instance de MutableLiveData est un objet LiveData et peut donc être référencée par une variable LiveData.
Maintenant, le tour est presque terminé. Vous exposez uniquement l'instance LiveData, personne ne peut utiliser ses méthodes protégées, ni ne peut la convertir en son super (peut-être au moment de la compilation, mais elle ne fonctionnerait pas: erreur RunTime). Et vous gardez l'instance de sous-classe réelle privée, de sorte qu'elle ne peut être modifiée que par ceux qui possèdent l'instance, en utilisant les méthodes de l'instance.
//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(.....)
Désormais, la super classe avertit lorsque des modifications sont appliquées.
//change the instance by using the sub class _name.postValue(...) //or _name.setValue(...)
Oui, c'est assez connu et cela décrit ci-dessus est un scénario courant. Supprimez le modèle d'observateur et créez-le simplement sous une forme set / get en bénéficierait tout autant. Selon ofc où vous l'implémentez, pas de règles d'or à la fin.
la source