web-dev-qa-db-fra.com

Notifier l'observateur lorsque l'élément est ajouté à la liste de LiveData

Je dois obtenir l'événement Observer lorsque l'élément est ajouté à la liste de LiveData. Mais si je comprends bien, l’événement ne reçoit que lorsque je remplace l’ancienne liste par une nouvelle. Par exemple quand je fais le suivant:

list.value = mutableListOf(IssuePost(UserEntity(name, email, photoUrl), issueEntity))

L'observateur obtient l'événement. Mais quand je viens d'ajouter un élément à la valeur, Observer est silencieux… .. Pourriez-vous s'il vous plaît donner un conseil sur la manière dont je peux mettre en œuvre ce dont j'ai besoin?

13
Ruslan Leshchenko

En interne, LiveData garde la trace de chaque modification sous la forme d’un numéro de version (un simple compteur stocké sous la forme d’un entier). L'appel de setValue () incrémente cette version et met à jour les nouvelles données des observateurs (uniquement si le numéro de version de l'observateur est inférieur à la version de LiveData).

Il semble que la seule façon de démarrer ce processus consiste à appeler setValue () ou postValue (). L'effet secondaire est que, si la structure de données sous-jacente de LiveData a été modifiée (par exemple, l'ajout d'un élément à une collection), il ne se passera rien pour le communiquer aux observateurs.

Ainsi, vous devrez appeler setValue () après avoir ajouté un élément à votre liste. J'ai fourni deux manières d'aborder cette question ci-dessous. J'aime mieux la première option.

Option 1

Conservez la liste en dehors de LiveData et mettez-la à jour avec la référence chaque fois que le contenu de la liste change.

private val mIssuePosts = ArrayList<IssuePost>()
private val mIssuePostLiveData = MutableLiveData<List<IssuePost>>()

fun addIssuePost(issuePost: IssuePost) {
   mIssuePosts.add(issuePost)
   mIssuePostLiveData.value = mIssuePosts
}

Option 2

Gardez une trace de la liste via LiveData et mettez à jour LiveData avec sa propre valeur chaque fois que le contenu de la liste change.

private val mIssuePostLiveData = MutableLiveData<List<IssuePost>>()

init {
   mIssuePostLiveData.value = ArrayList()
}

fun addIssuePost(issuePost: IssuePost) {
    mIssuePostLiveData.value?.add(issuePost)
    mIssuePostLiveData.value = mIssuePostLiveData.value
}

L'une ou l'autre de ces solutions devrait vous éviter d'avoir à créer une nouvelle liste chaque fois que vous modifiez la liste actuelle uniquement pour informer les observateurs.

17
Programmer001

J'utilise un Kotlin Extension Function pour faciliter les choses:

fun <T> MutableLiveData<T>.notifyObserver() {
    this.value = this.value
}

Puis utilisez-le dans n'importe quelle MutableLiveData comme ceci:

fun addIssuePost(issuePost: IssuePost) {
    mIssuePostLiveData.value?.add(issuePost)
    mIssuePostLiveData.notifyObserver()
}
4
Gnzlt

Que dis-tu de ça?

public class ListLiveData<T> extends LiveData<List<T>> {
    public void addAll(List<T> items) {
        if (getValue() != null && items != null) {
            getValue().addAll(items);
            setValue(getValue());
        }
    }

    public void clear() {
        if (getValue() != null) {
            getValue().clear();
            setValue(getValue());
        }
    }

    @Override public void setValue(List<T> value) {
        super.setValue(value);
    }

    @Nullable @Override public List<T> getValue() {
        return super.getValue();
    }
}

// add changed listener
    mMessageList.observe(mActivity, new Observer() {
        @Override public void onChanged(@Nullable Object o) {
            notifyDataSetChanged();
        }
    });
1
user3682351

Inspirée de @ user3682351, voici ma solution ..__ Il semble que nous ne puissions pas mettre à jour les propriétés d'une valeur LiveData individuellement; la valeur doit donc être mise à jour à chaque opération. Il s’agit essentiellement d’un petit wrapper sur des données en temps réel avec des méthodes pratiques pour modifier les propriétés d’une variable HashMap

import androidx.lifecycle.LiveData

/**
 * Hash Map Live Data
 *
 * Some convenience methods around live data for HashMaps. Putting a value on this will also update the entire live data
 * as well
 */
class HashMapLiveData<K, V> : LiveData<HashMap<K, V>>() {

    /**
     * Put a new value into this HashMap and update the value of this live data
     * @param k the key
     * @param v the value
     */
    fun put(k: K, v: V) {
        val oldData = value
        value = if (oldData == null) {
            hashMapOf(k to v)
        } else {
            oldData.put(k, v)
            oldData
        }
    }

    /**
     * Add the contents to the HashMap if there is one existing, otherwise set the value to this HashMap and update the
     * value of this live data
     * @param newData the HashMap of values to add
     */
    fun putAll(newData: HashMap<K, V>) {
        val oldData = value
        value = if (oldData != null) {
            oldData.putAll(newData)
            oldData
        } else {
            newData
        }
    }

    /**
     * Remove a key value pair from this HashMap and update the value of this live data
     * @param key the key to remove
     */
    fun remove(key: K) {
        val oldData = value
        if (oldData != null) {
            oldData.remove(key)
            value = oldData
        }
    }

    /**
     * Clear all data from the backing HashMap and update the value of this live data
     */
    fun clear() {
        val oldData = value
        if (oldData != null) {
            oldData.clear()
            value = oldData
        }
    }

    var value: HashMap<K, V>?
        set(value) = super.setValue(value)
        get() = super.getValue()

}

0
William Reed