J'ai observé que MutableLiveData
déclenche onChanged
d'un observateur même si la même instance d'objet est fournie à sa méthode setValue
.
class DistinctLiveData<T> : MutableLiveData<T>() { private var cached: T? = null @Synchronized override fun setValue(value: T) { if(value != cached) { cached = value super.setValue(value) } } @Synchronized override fun postValue(value: T) { if(value != cached) { cached = value super.postValue(value) } } }
Existe-t-il un moyen d'éviter qu'un observateur ne soit notifié deux fois si la même instance ou une instance équivalente est fournie à setValue ()
/ postValue ()
J'ai essayé d'étendre MutableLiveData
mais cela n'a pas fonctionné. Il se peut que je manque quelque chose ici
//Fragment#onCreateView - scenario1 val newValue = "newValue" mutableLiveData.setValue(newValue) //triggers observer mutableLiveData.setValue(newValue) //triggers observer //Fragment#onCreateView - scenario2 val newValue = "newValue" mutableLiveData.postValue(newValue) //triggers observer mutableLiveData.postValue(newValue) //does not trigger observer
4 Réponses :
Vous pouvez utiliser le tour de magie suivant pour consommer "les éléments étant identiques":
fun <T> LiveData<T>.distinctUntilChanged(): LiveData<T> = MediatorLiveData<T>().also { mediator -> mediator.addSource(this, object : Observer<T> { private var isInitialized = false private var previousValue: T? = null override fun onChanged(newValue: T?) { val wasInitialized = isInitialized if (!isInitialized) { isInitialized = true } if(!wasInitialized || newValue != previousValue) { previousValue = newValue mediator.postValue(newValue) } } }) }
Si vous voulez vérifier l'égalité référentielle, c'est ! ==
.
Il existe déjà dans l'API: Transformations.distinctUntilChanged ()
public static LiveData<X> distinctUntilChanged (LiveData<X> source)Crée un nouvel objet
LiveData
n'émet pas de valeur tant que la source La valeur LiveData a été modifiée. La valeur est considérée comme modifiée siequals ()
donnefalse
.>
Étant donné que cela a été signalé comme une réponse possible avec lien uniquement, j'ai extrait un peu de la documentation.
Il convient de mentionner que Transformations.distingUntilChanged ()
est disponible au plus tôt dans la version 2.1.0 qui n'est pas encore une version stable! developer.android.com/jetpack/androidx/releases/… < / a>
mise à jour: il est maintenant dans la version stable. sûr à utiliser.
Si nous parlons de MutableLiveData
, vous pouvez créer une classe et remplacer setValue, puis n'appeler via super que si nouvelle valeur! = ancienne valeur
class DistinctUntilChangedMutableLiveData<T> : MutableLiveData<T>() { override fun setValue(value: T?) { if (value != this.value) { super.setValue(value) } } }
Je ne sais pas pourquoi cela n'a pas obtenu plus de votes positifs, semble le moyen le plus simple et le plus propre à imo.
Oui, vous devez savoir comment fonctionne l'égalité, mais ne vous trompez pas.
@ bastami82: Veuillez arrêter de changer ma réponse. Corrigez mes fautes de frappe, ajoutez un peu de mise en forme, c'est bien, pour toute autre chose, écrivez votre propre réponse.
j'ai juste essayé d'être utile car mes modifications suggérées n'ont PAS changé l'essence de votre réponse, j'aurais pu écrire ma propre réponse, vous avez raison, mais je pensais que, compte tenu de votre réponse, malheureusement, vous n'avez pas apprécié l'effort (au fait c'est ainsi que le code évolue). À mon avis, les changements suggérés l'ont rendu plus clair, je pensais seulement que c'était une bonne réponse et qu'il fallait un peu de polissage, déçu que vous ne l'aimiez pas mais je respecte votre décision.
Dans mon cas, j'ai des objets assez complexes que je dois comparer par certains champs. Pour cela, j'ai changé la réponse d'EpicPandaForce:
fun <T> LiveData<T>.distinctUntilChanged(compare: T?.(T?) -> Boolean = { this == it }): LiveData<T> = MediatorLiveData<T>().also { mediator -> mediator.addSource(this) { newValue -> if(!newValue.compare(value)) { mediator.postValue(newValue) } } }
Par défaut, il utilise la méthode standard equals
, mais si vous avez besoin - vous pouvez changer la logique de distinction