Diferença de setValue () e postValue () em MutableLiveData

105

Existem duas maneiras de alterar o valor de MutableLiveData. Mas qual é a diferença entre setValue()e postValue()em MutableLiveData.

Não consegui encontrar documentação para o mesmo.

Aqui está a aula 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);
    }
}
Khemraj
fonte

Respostas:

178

Com base na documentação:

setValue () :

Define o valor. Se houver observadores ativos, o valor será despachado para eles. Este método deve ser chamado a partir do thread principal.

postValue () :

Publica uma tarefa em um thread principal para definir o valor fornecido. Se você chamar esse método várias vezes antes de um thread principal executar uma tarefa postada, apenas o último valor será despachado.

Para resumir, a principal diferença seria:

setValue()método deve ser chamado a partir do thread principal. Mas se você precisar definir um valor de um thread de segundo plano, postValue()deve ser usado.

Sagar
fonte
"apenas o último valor seria despachado". Não posso ter certeza sobre isso lendo o código. Portanto, parece que quando o primeiro thread está prestes a atingir o bloco sincronizado interno dentro de postValue (), a próxima janela da CPU pode ser potencialmente fornecida ao thread 2 que está postando outro valor. O thread 2 pode então completar o bloco sincronizado e o planejador dá ao primeiro thread uma janela para ser executado. Agora, ele sobrescreve o que o thread 2 já escreveu. Isso é possível?
stdout
97

Todas as respostas acima estão corretas. Mas mais uma diferença importante. Se você chamar postValue()em um campo que não tem observadores e depois ligar getValue(), você não receberá o valor que definiu em postValue(). Portanto, tome cuidado se você trabalhar em threads de fundo sem observadores.

w201
fonte
3
Gostaria de poder triplicar o voto! Com base nisso, parece que é melhor usar, setValue()se possível, e usar 'postValue ()' com cautela, apenas quando necessário. Obrigado
jungledev
1
Não, aqui não existe nenhuma "melhor" maneira. Se você trabalha com seu LiveData a partir de um thread de segundo plano, deve usar postValue. Também na última versão dos componentes do ciclo de vida, ele corrigiu ... provavelmente.
w201
"Também na última versão dos componentes do ciclo de vida, ela corrigiu ... provavelmente." Você tem mais informações sobre isso? Obrigado
Chris Nevill
1
Fiz alguns testes e parece que com a última versão do lib tudo funciona como deveria.
w201
Você poderia me mostrar o código acima de forma concreta? Se em ViewModel, implementei como noObserveLiveData.postValue("sample"), em atividade, quando usei getValue como viewModel.noObserveLiveData.getValueVocê quer dizer que não é o valor que defini em postValue () ("amostra")?
kwmt
14

setValue()é chamado diretamente do thread do chamador, notifica os observadores de forma síncrona e altera o LiveDatavalor imediatamente. Ele pode ser chamado apenas a partir de MainThread.
postValue()usa dentro de algo como isso new Handler(Looper.mainLooper()).post(() -> setValue()), então ele é executado setValueatravés Handlerde MainThread. Ele pode ser chamado de qualquer thread.

Ufkoku
fonte
11

setValue()

Define o valor. Se houver observadores ativos, o valor será despachado para eles.

Este método deve ser chamado a partir do thread principal .

postValue

Se você precisar definir um valor de um thread de segundo plano, você pode usar postValue(Object)

Publica uma tarefa em um thread principal para definir o valor fornecido.

Se você chamar esse método várias vezes antes de um thread principal executar uma tarefa postada, apenas o último valor será despachado.

Nilesh Rathod
fonte
5

Esta não é uma resposta direta ao problema acima. As respostas de Sagar e w201 são fantásticas. Mas uma regra prática simples que uso em ViewModels para MutableLiveData é:

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

Substitua mutValpelo valor desejado.

Himujjal Upadhyaya
fonte
Legal, eu gosto disso. Em Kotlin, criei uma extensão que encapsula a atualização inteligente para que as inúmeras atualizações de valor em todo o meu aplicativo sejam uma chamada única e consistente.
19Craig
4

setValue()método deve ser chamado a partir do thread principal. Se você precisar definir um valor de um thread de segundo plano, você pode usarpostValue() .

Mais aqui .

Levon Petrosyan
fonte
0

Em nosso aplicativo, usamos um LiveData único que contém dados para várias visualizações em uma atividade / tela. Basicamente, N não de conjuntos de dados para N de visualizações. Isso nos incomodou um pouco, devido à forma como o postData foi projetado. E temos objeto de estado em LD que transmite a visão sobre qual visão precisa ser atualizada.

então LD se parece com isto:

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

Existem algumas visualizações (view_1 e view_2) que tiveram que ser atualizadas quando um evento ocorre ... significa que elas devem ser notificadas ao mesmo tempo quando o evento ocorre. Então, liguei:

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

Isso não funcionaria por razões que conhecemos.

O que entendi é que basicamente um LD deve representar apenas uma visão. Então, não há chance de você ter que chamar postData () duas vezes seguidas. Mesmo se você chamar, a maneira como postData lida com isso para você é o que você também esperaria (mostrando os dados mais recentes para você na visualização). Tudo cai bem no lugar.

Um LD -> uma Visualização. PERFEITO

Um LD -> visualizações múltiplas PODE EXISTIR UM COMPORTAMENTO ESTRANHO

cgr
fonte