No ponto de vista da execução de código no thread da interface do usuário, existe alguma diferença entre:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
ou
MainActivity.this.myView.post(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
e
private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
protected void onPostExecute(Bitmap result) {
Log.d("UI thread", "I am the UI thread");
}
}
Respostas:
Nenhum deles é exatamente o mesmo, embora todos tenham o mesmo efeito líquido.
A diferença entre o primeiro e o segundo é que, se você estiver no encadeamento principal do aplicativo ao executar o código, o primeiro (
runOnUiThread()
) executará oRunnable
imediatamente. O segundo (post()
) sempre coloca oRunnable
final da fila de eventos, mesmo se você já estiver no encadeamento principal do aplicativo.O terceiro, supondo que você crie e execute uma instância de
BackgroundTask
, perderá muito tempo capturando um encadeamento do conjunto de encadeamentos, para executar um no-op padrãodoInBackground()
, antes de, eventualmente, fazer o que equivale a apost()
. Este é de longe o menos eficiente dos três. UseAsyncTask
se você realmente tiver trabalho a fazer em um encadeamento em segundo plano, não apenas pelo uso deonPostExecute()
.fonte
AsyncTask.execute()
requer que você chame a partir do thread da interface do usuário de qualquer maneira, o que torna essa opção inútil para o caso de uso de simplesmente executar código no thread da interface do usuário a partir de um thread de segundo plano, a menos que você mova todo o seu trabalho em segundo planodoInBackground()
e o useAsyncTask
adequadamente.AsyncTask
do thread da interface do usuário?boolean isUiThread = (Looper.getMainLooper().getThread() == Thread.currentThread());
Looper.getMainLooper().isCurrentThread
Eu gosto do comentário do HPP , ele pode ser usado em qualquer lugar sem nenhum parâmetro:
fonte
Existe uma quarta maneira de usar
Handler
fonte
new Handler(Looper.getMainLooper()).post(r)
, que é a maneira preferida comoLooper.getMainLooper()
faz uma chamada estática para main, enquanto quepostOnUiThread()
deve ter uma instânciaMainActivity
no escopo.A resposta de Pomber é aceitável, no entanto, não sou muito fã de criar novos objetos repetidamente. As melhores soluções são sempre as que tentam atenuar a memória. Sim, existe uma coleta automática de lixo, mas a conservação da memória em um dispositivo móvel está dentro dos limites das melhores práticas. O código abaixo atualiza um TextView em um serviço.
Pode ser usado em qualquer lugar como este:
fonte
The best solutions are always the ones that try to mitigate memory hog
. Existem muitos outros critérios parabest
, e isso tem um leve cheiro depremature optimization
. Ou seja, a menos que você saiba que está chamando o suficiente, o número de objetos criados é um problema (em comparação com as dez mil outras maneiras pelas quais seu aplicativo provavelmente está criando lixo.), O que pode serbest
é escrever o mais simples (mais fácil de entender) ) e passe para outra tarefa.textViewUpdaterHandler
seria melhor nomeado algo comouiHandler
oumainHandler
, pois geralmente é útil para qualquer postagem no thread da interface principal; não está vinculado à sua classe TextViewUpdater. Eu o afastaria do restante desse código e deixaria claro que ele pode ser usado em outro lugar ... O restante do código é duvidoso, porque, para evitar a criação dinâmica de um objeto, você divide o que poderia ser uma única chamada. duas etapassetText
epost
, que dependem de um objeto de longa duração que você usa como temporário. Complexidade desnecessária e não segura para threads. Não é fácil de manter.uiHandler
etextViewUpdater
, em seguida, melhorar a sua classe, alterando apublic void setText(String txt, Handler uiHandler)
e adicionando linha métodouiHandler.post(this);
Então chamador pode fazer em uma única etapa:textViewUpdater.setText("Hello", uiHandler);
. Então, no futuro, se precisar ser seguro para threads, o método poderá agrupar suas instruções dentro de um bloqueiouiHandler
e o chamador permanecerá inalterado.No Android P, você pode usar
getMainExecutor()
:Dos documentos do desenvolvedor do Android :
Do CommonsBlog :
fonte
Se você precisar usar o Fragment, use
ao invés de
Porque haverá uma exceção de ponteiro nulo em algumas situações, como fragmento de pager
fonte
oi pessoal, essa é uma pergunta básica, qualquer coisa que eu digo
use Handler
fonte
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
se não for chamado a partir do thread da interface do usuário.