Différence de setValue () et postValue () dans MutableLiveData

107

Il existe deux façons de valoriser le changement MutableLiveData. Mais quelle est la différence entre setValue()& postValue()in MutableLiveData.

Je n'ai pas pu trouver de documentation pour le même.

Voici la classe MutableLiveDatad'Android.

package android.arch.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);
    }
}
Khemraj
la source

Réponses:

179

Basé sur la documentation:

setValue () :

Définit la valeur. S'il y a des observateurs actifs, la valeur leur sera envoyée. Cette méthode doit être appelée à partir du thread principal.

postValue () :

Publie une tâche sur un thread principal pour définir la valeur donnée. Si vous avez appelé cette méthode plusieurs fois avant qu'un thread principal n'exécute une tâche publiée, seule la dernière valeur serait distribuée.

Pour résumer, la principale différence serait:

setValue()La méthode doit être appelée à partir du thread principal. Mais si vous avez besoin de définir une valeur à partir d'un thread d'arrière-plan, postValue()doit être utilisé.

Sagar
la source
"seule la dernière valeur serait envoyée". Je ne peux pas en être sûr en lisant le code. Il semble donc qu'une fois que le premier thread est sur le point d'atteindre le bloc synchronisé interne à l'intérieur de postValue (), la fenêtre CPU suivante peut potentiellement être donnée au thread 2 qui publie une autre valeur. Le thread 2 peut alors terminer le bloc synchronisé et le planificateur donne au premier thread une fenêtre pour qu'il s'exécute. Maintenant, il remplace ce que le thread 2 a déjà écrit. Est-ce possible?
stdout le
98

Toutes les réponses ci-dessus sont correctes. Mais une autre différence importante. Si vous appelez un postValue()champ qui n'a pas d'observateurs et que vous appelez ensuite getValue(), vous ne recevez pas la valeur que vous avez définie postValue(). Soyez donc prudent si vous travaillez dans des threads d'arrière-plan sans observateurs.

w201
la source
3
J'aimerais pouvoir voter trois fois! Sur cette base, il semble qu'il soit préférable d'utiliser setValue()si possible, et d'utiliser prudemment «postValue ()», uniquement lorsque cela est nécessaire. Merci
jungledev
1
Non, il n'y a pas de «meilleur» moyen. Si vous travaillez avec votre LiveData à partir d'un fil d'arrière-plan, vous devez utiliser postValue. Également dans la dernière version des composants du cycle de vie, il a été corrigé ... probablement.
w201
"Également dans la dernière version des composants du cycle de vie, il a été corrigé ... probablement." Avez-vous plus d'informations à ce sujet? Merci
Chris Nevill
1
J'ai fait quelques tests et il semble qu'avec la dernière version de lib tout fonctionne comme il se doit.
w201
Pouvez-vous me montrer concrètement le code ci-dessus? Si dans ViewModel, j'ai implémenté comme noObserveLiveData.postValue("sample"), dans l'activité, quand j'ai utilisé getValue comme viewModel.noObserveLiveData.getValueVoulez-vous dire N'est-ce pas la valeur que j'ai définie dans postValue () ("sample")?
kwmt
14

setValue()est appelé directement à partir du thread de l'appelant, notifie les observateurs de manière synchrone et modifie la LiveDatavaleur immédiatement. Il ne peut être appelé qu'à partir de MainThread.
postValue()utilise à l'intérieur quelque chose comme ça new Handler(Looper.mainLooper()).post(() -> setValue()), donc il s'exécute setValuevia Handlerdans MainThread. Il peut être appelé depuis n'importe quel thread.

Ufkoku
la source
11

setValue()

Définit la valeur. S'il y a des observateurs actifs, la valeur leur sera envoyée.

Cette méthode doit être appelée à partir du thread principal .

postValue

Si vous avez besoin de définir une valeur à partir d'un thread d'arrière-plan, vous pouvez utiliser postValue(Object)

Publie une tâche sur un thread principal pour définir la valeur donnée.

Si vous avez appelé cette méthode plusieurs fois avant qu'un thread principal n'exécute une tâche publiée, seule la dernière valeur serait distribuée.

Nilesh Rathod
la source
5

Ce n'est pas une réponse directe au problème ci-dessus. Les réponses de Sagar et w201 sont géniales. Mais une règle de base simple que j'utilise dans ViewModels pour MutableLiveData est:

private boolean isMainThread() {
    return Looper.myLooper() == Looper.getMainLooper();
}

private MutableLiveData<Boolean> mutVal = new MutableLiveData<>(false);
public LiveData<Boolean> getMutVal() { return this.mutVal;  }
public void setMutVal(boolean val) {
    if (isMainThread()) mutVal.setValue(val);
    else mutVal.postValue(val);
}

Remplacez mutValpar la valeur souhaitée.

Himujjal Upadhyaya
la source
Bien, j'aime ça. Dans Kotlin, j'ai créé une extension qui encapsule la mise à jour intelligente afin que les nombreuses mises à jour de valeur dans mon application soient un appel unique et cohérent.
19Craig
4

setValue()La méthode doit être appelée à partir du thread principal. Si vous avez besoin de définir une valeur à partir d'un thread d'arrière-plan, vous pouvez utiliserpostValue() .

Plus ici .

Levon Petrosyan
la source
0

Dans notre application, nous avions utilisé un seul LiveData qui contient des données pour plusieurs vues dans une activité / un écran. Fondamentalement, N pas de jeux de données pour N pas de vues. Cela nous a un peu dérangés parce que la façon dont postData est conçu. Et nous avons un objet d'état dans LD qui indique quelle vue doit être mise à jour.

donc LD ressemble à ceci:

LD {
   state (view_1, view_2, view_3 …),
   model_that_contains_data_of_all_views
}

Il y a quelques vues (view_1 et view_2) qui ont dû être mises à jour lorsqu'un événement se produit. Cela signifie qu'elles doivent être notifiées en même temps lorsqu'un événement se produit. Alors, j'ai appelé:

postData(LD(view_1, data))
postData(LD(view_2, data)

Cela ne fonctionnerait pas pour des raisons que nous connaissons.

Ce que j'ai compris, c'est que fondamentalement, un LD ne devrait représenter qu'une seule vue. Alors il n'y a aucune chance que vous ayez à appeler postData () deux fois de suite. Même si vous appelez, la façon dont postData le gère pour vous est ce à quoi vous vous attendez également (montrant les dernières données pour vous). Tout tombe bien en place.

Un LD -> une vue. PARFAIT

Un LD -> plusieurs vues IL PEUT ÊTRE UN COMPORTEMENT ÉTRANGE

cgr
la source