Diferencia de setValue () y postValue () en MutableLiveData


107

Hay dos formas de hacer que el cambio valga la pena MutableLiveData. Pero, ¿cuál es la diferencia entre setValue()& postValue()in MutableLiveData.

No pude encontrar documentación para el mismo.

Aquí está la clase MutableLiveDatade 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);
    }
}

Respuestas:


179

Basado en la documentación:

setValue () :

Establece el valor. Si hay observadores activos, se les enviará el valor. Este método debe llamarse desde el hilo principal.

postValue () :

Publica una tarea en un hilo principal para establecer el valor dado. Si llamó a este método varias veces antes de que un hilo principal ejecutara una tarea publicada, solo se enviaría el último valor.

Para resumir, la diferencia clave sería:

setValue()se debe llamar al método desde el hilo principal. Pero si necesita establecer un valor de un hilo de fondo, postValue()debe usarse.


"sólo se enviará el último valor". No puedo estar seguro leyendo el código. Por lo tanto, parece que una vez que el primer hilo está a punto de golpear el bloque sincronizado interno dentro de postValue (), la siguiente ventana de CPU se puede entregar potencialmente al hilo 2 que está publicando otro valor. El hilo 2 puede luego completar el bloque sincronizado y el planificador le da al primer hilo una ventana para que se ejecute. Ahora, sobreescribe lo que el hilo 2 ya ha escrito. es posible?
salida

98

Todas las respuestas anteriores son correctas. Pero una diferencia más importante. Si llama postValue()a un campo que no tiene observadores y luego llama getValue(), no recibe el valor que estableció postValue(). Así que tenga cuidado si trabaja en subprocesos en segundo plano sin observadores.


3
¡Ojalá pudiera triple-upvote! En base a esto, parece que es mejor usarlo setValue()si es posible, y usar con precaución 'postValue ()', solo cuando sea necesario. Gracias
jungledev

1
No, aquí no hay una "mejor" manera. Si trabaja con su LiveData desde un hilo en segundo plano, debe usar postValue. También en la última versión de los componentes del ciclo de vida se corrigió ... probablemente.
w201

"También en la última versión de los componentes del ciclo de vida se corrigió ... probablemente". ¿Tienes más información sobre esto? Gracias
Chris Nevill

1
Hice algunas pruebas y parece que con la última versión de lib todo funciona como debería.
w201

¿Podría mostrarme el código de arriba en concreto? Si en ViewModel, implementé como noObserveLiveData.postValue("sample"), En Actividad, cuando usé getValue como viewModel.noObserveLiveData.getValue¿Quieres decir que no es el valor que establecí en postValue () ("muestra")?
kwmt

14

setValue()se llama directamente desde el hilo de llamada, notifica sincrónicamente a los observadores y cambia el LiveDatavalor inmediatamente. Solo se puede llamar desde MainThread.
postValue()usa dentro de algo como esto new Handler(Looper.mainLooper()).post(() -> setValue()), por lo que se ejecuta a setValuetravés Handlerde MainThread. Se puede llamar desde cualquier hilo.


11

setValue()

Establece el valor. Si hay observadores activos, se les enviará el valor.

Este método debe llamarse desde el hilo principal .

postValue

Si necesita establecer un valor de un hilo en segundo plano, puede usar postValue(Object)

Publica una tarea en un hilo principal para establecer el valor dado.

Si llamó a este método varias veces antes de que un hilo principal ejecutara una tarea publicada, solo se enviaría el último valor.


5

Esta no es una respuesta directa al problema anterior. Las respuestas de Sagar y w201 son impresionantes. Pero una regla general simple que uso en ViewModels para MutableLiveData es:

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);
}

Reemplace mutValcon su valor deseado.


Bien, me gusta esto. En Kotlin, creé una extensión que encapsula la actualización inteligente para que las numerosas actualizaciones de valor en toda mi aplicación sean una llamada única y consistente.
19Craig

4

setValue()se debe llamar al método desde el hilo principal. Si necesita establecer un valor de un hilo en segundo plano, puede usarpostValue() .

Más aquí .


0

En nuestra aplicación, usamos LiveData único que contiene datos para múltiples vistas en una actividad / pantalla. Básicamente N número de conjuntos de datos para N número de vistas. Esto nos preocupó un poco debido a la forma en que está diseñado postData. Y tenemos un objeto de estado en LD que transmite una vista sobre qué vista necesita actualizarse.

entonces LD se ve así:

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

Hay un par de vistas (vista_1 y vista_2) que debían actualizarse cuando se produce un evento ... lo que significa que deberían recibir una notificación al mismo tiempo cuando ocurre un evento. Entonces, llamé:

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

Esto no funcionaría por razones que conocemos.

Lo que entendí es que básicamente un LD debería representar solo una vista. Entonces no hay posibilidad de que tenga que llamar a postData () dos veces seguidas. Incluso si llama, la forma en que postData lo maneja es lo que también esperaría (mostrando los últimos datos a la vista). Todo cae bien en su lugar.

Un LD -> una vista. PERFECTO

Un LD -> múltiples vistas PUEDE HABER UN COMPORTAMIENTO EXTRAÑO

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.