106 votes

Pourquoi existe-t-il une sous-classe MutableLiveData distincte de LiveData ?

On dirait que MutableLiveData diffère de LiveData seulement en faisant le setValue() y postValue() publiques, alors que dans LiveData ils sont protégés.

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 dans le fichier de configuration de l'entreprise ? LiveData elle-même ?

D'une manière générale, une telle forme d'héritage (augmenter la visibilité de certaines méthodes étant le seul changement) est-elle une pratique bien connue et quels sont les scénarios où elle peut être utile (en supposant que nous ayons accès à tout le code) ?

12 votes

Il s'agit d'une décision de conception. LiveData est immuable, puisque le client ne peut pas modifier l'état interne, et est donc à l'abri des fils.

151voto

Sneh Pandya Points 4033

Sur LiveData - Documentation pour les développeurs Android vous pouvez voir que pour LiveData , setValue() & postValue() ne sont pas publiques.

considérant que, dans MutableLiveData - Documentation pour les développeurs Android vous pouvez le voir, MutableLiveData étend LiveData en interne et également les deux méthodes magiques de LiveData es publiquement disponibles dans ce domaine et ils sont setValue() & postValue() .

setValue() pour fixer la valeur et la distribuer à tous les observateurs actifs, doit être appelé à partir de fil conducteur .

postValue() : envoyer une tâche au thread principal pour remplacer la valeur fixée par setValue() doit être appelé à partir de fil de fond .

Donc, LiveData es immuable . MutableLiveData es LiveData qui est mutable & Sécurité des fils .

50 votes

Ce n'est pas vraiment que LiveData est immuable, juste qu'il ne peut pas être modifié à l'extérieur de de la classe ViewModel. La classe ViewModel peut le modifier comme elle le souhaite (par exemple, un ViewModel à minuterie). Vous utiliseriez MutableLiveData si vous vouliez le modifier en dehors de la classe ViewModel.

0 votes

Dans quels scénarios dois-je utiliser la classe livedata personnalisée ?

2 votes

Prenons ce scénario, une application avec le modèle de référentiel (serveur + salle) où la salle est la source unique de vérité. L'application ne reçoit des données que de la salle, tandis que la salle reçoit ses mises à jour du serveur. Est-ce que mutableLiveData doit être utilisé parce que les données du serveur mettent à jour la salle, ou est-ce que LiveData peut être utilisé ?

15voto

Ananth Raj Singh Points 494

C'est l'ensemble MutableLiveData.java fichier :

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 qu'en faisant postValue y setValue public.

Un cas d'utilisation qui me vient à l'esprit est celui de l'encapsulation avec l'utilisation de Propriété du support en Kotlin. Vous pouvez exposer LiveData à votre Fragment/Activité (contrôleur d'interface utilisateur) même si vous pouvez avoir MutableLiveData pour la manipulation dans votre ViewModel 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 pourra seulement observer les valeurs sans pouvoir les modifier. Évidemment, votre contrôleur d'interface utilisateur peut modifier les valeurs à l'aide des méthodes publiques de l'élément TempViewModel comme incrementCount() .

Note : 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
}

0 votes

Qu'est-ce que _score ?

0 votes

Bien répondu. Merci

5voto

Khamaseen Points 64

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. Ainsi, dans ce cas, MutableLiveData étant une sous-classe de LiveData peut accéder à ces méthodes protégées.

Ce que vous voulez faire, c'est observer une instance et voir s'il y a des changements. Mais en même temps, vous ne voulez pas que des "étrangers" modifient l'instance que vous observez. Dans un sens, cela crée un problème, car vous aimeriez avoir un objet qui soit à la fois modifiable, pour mettre à jour tout nouveau statut, et non modifiable, pour vous assurer que personne qui ne le devrait ne puisse mettre à jour cette instance. Ces deux caractéristiques entrent en conflit l'une avec l'autre mais peuvent être résolues en créant une couche supplémentaire.

Il s'agit donc 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 pouvez maintenant commencer à créer des instances, et créer votre instance d'observateur de MutableLiveData. Dans le 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 fait. Vous n'exposez que l'instance de LiveData, personne ne peut utiliser ses méthodes protégées, ni faire un cast vers sa super classe (peut-être au moment de la compilation, mais cela ne fonctionnerait pas : erreur RunTime). Et vous gardez l'instance de la sous-classe 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 est avertie lorsque des modifications sont appliquées.

//change the instance by using the sub class
_name.postValue(...)
//or _name.setValue(...)

Citation en bloc D'une manière générale, une telle forme d'héritage (augmenter la visibilité de certaines méthodes étant le seul changement) est-elle une pratique bien connue et quels sont les scénarios où elle peut être utile (en supposant que nous ayons accès à tout le code) ?

Oui, c'est bien connu et le scénario décrit ci-dessus est courant. Si l'on supprime le modèle de l'observateur et qu'on le présente sous la forme d'un ensemble/objet, on peut en tirer tout autant de bénéfices. Cela dépend bien sûr de l'endroit où vous l'implémentez, il n'y a pas de règle d'or en fin de compte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X