Android: quando devo usar um Handler () e quando devo usar um Thread?

129

Quando eu preciso de algo para executar de forma assíncrona , como uma tarefa de longa duração ou uma lógica que usa a rede, ou por qualquer motivo, iniciar um novo thread e executá-lo funcionam bem. Criar um manipulador e executá-lo também funcionam. Qual é a diferença? Quando devo usar cada um? Quais são as vantagens / razões para usar a Handlere não a Thread?

PS. - Por esta questão, vamos ignorar AsyncTask. - o Handler().postDelayedcaso de uso é claro para mim, pelo bem desta pergunta, vamos supor que preciso que a tarefa seja iniciada imediatamente.

JRun
fonte
Na sua situação, siga em frente e use um novo Thread, minha próxima sugestão seria o AsyncTask, mas não é isso que você deseja com clareza. Os manipuladores são usados ​​principalmente se você deseja adicionar um atraso ou algum outro tipo de personalização a um executável.
kabuto178
1
@ kabuto178 bem, existem outros benefícios dos manipuladores que vale a pena mencionar que você pulou. Como, por exemplo, poder interagir com o thread da interface do usuário a partir de um thread separado.
tony9099

Respostas:

168

Se o que você estiver fazendo for "pesado", deverá fazê-lo em um Thread. Se você não iniciá-lo explicitamente em seu próprio encadeamento, ele será executado no encadeamento principal (UI) que pode ser percebido como instável ou lento para responder à interface de seus usuários.

Curiosamente, quando você está usando um encadeamento, geralmente é útil usar um manipulador como um meio de comunicação entre o encadeamento de trabalho que você está iniciando e o encadeamento principal.

Uma interação típica Thread / Handler pode ser algo como isto:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

Em geral, porém, o que você leva para casa é que você deve usar um Thread sempre que estiver executando algum trabalho que possa ser demorado ou muito intenso (ou seja, qualquer rede, IO de arquivo, aritmética pesada, etc.).

FoamyGuy
fonte
Obrigado pela resposta rápida e a quantidade de tempo investido (e a velocidade da sua resposta !!)! Então, deixe-me ver se entendi: Handler foi projetado para facilitar a comunicação sem bloqueio entre os threads de trabalho e o thread da interface do usuário?
JRun
3
@JRun Esse é um dos usos sim. Confira a descrição do manipulador nos documentos java para obter ótimas informações sobre ele. Incluindo outro de seus usos (para agendar mensagens e executáveis ​​para serem executados como algum ponto no futuro).
FoamyGuy
bem explicado @FoamyGuy!
tony9099
Olá, é garantido que updateUI()será executado depois onCreateView(após o carregamento de novas visualizações)?
Zyoo
1
Por que é isso message.what()? Não seria apenas if(msg == 0){? Muito obrigado! :)
Ruchir Baronia
64

Handler e Thread são realmente duas coisas diferentes.

Um encadeamento deve ser criado para executar trabalhos de execução longa.

Um manipulador é um objeto muito conveniente para se comunicar entre 2 threads (por exemplo: um thread em segundo plano precisa atualizar a interface do usuário. Você pode usar um manipulador para publicar alguns Runnable do thread em segundo plano no thread da interface do usuário).

Portanto, você não tem escolha entre Manipulador ou Thread. Use um thread para fazer trabalhos pesados! (você pode usar um manipulador se o encadeamento em segundo plano acionar algum trabalho a ser realizado em outro encadeamento - na maioria das vezes o encadeamento da interface do usuário)

ben75
fonte
Obrigado pela resposta rápida e a quantidade de tempo investido (e a velocidade da sua resposta !!)!
JRun
28

Handlere Threadsão duas coisas diferentes, mas elas não se contradizem. Você pode ter um Handlere um Threadao mesmo tempo e, na verdade, cada um Handlerdeve estar executando em um Thread.

Para mais detalhes, consulte este artigo .

insira a descrição da imagem aqui

pierrotlefou
fonte
19

A Handleré executado da mesma forma Thread, a Threadé executado em um thread diferente.

Use um manipulador se precisar executar algo no mesmo encadeamento , geralmente um elemento da GUI ou algo assim.

Use um Thread se quiser manter o thread principal livre para fazer outras coisas . Use isso para qualquer coisa que leve uma quantidade significativa de tempo.

PearsonArtPhoto
fonte
6
por que devo usar um manipulador se quero executar algo no mesmo thread? qual é o objetivo do método mHandler.post (...)?
Elias
1
Elias, nesse caso, você pode usar o manipulador se desejar que uma determinada tarefa seja executada após um certo período de tempo ou que repita uma tarefa a cada X vezes. Se você não quiser usar essas coisas, está certo. não é digno usar um manipulador. você pode simplesmente fazer as coisas da GUI ali mesmo e, de qualquer forma, porque você está no encadeamento da interface do usuário, porque o manipulador é executado no encadeamento em que foi criado.
tony9099
14

Manipuladores são a melhor maneira de comunicação entre o segundo plano e o thread da interface do usuário. Geralmente, os manipuladores são associados à fila de mensagens de um segmento e são usados ​​para enviar mensagens e executáveis ​​para a mensagem.

USAR:

Encadeamento: para executar tarefas no encadeamento saperate (plano de fundo) que no encadeamento da interface do usuário. (ajuda a desbloquear o thread da interface do usuário)

Manipulador Usado para se comunicar entre a interface do usuário e o thread de segundo plano.

Dê uma olhada neste artigo

Saubhagya Ranjan Das
fonte
4

Se você precisar atualizar a interface do usuário a partir de um novo Thread, precisará sincronizar com o thread da interface do usuário.

Você pode usar a classe android.os.Handler ou a classe AsyncTasks para isso.

A classe Handler pode atualizar a interface do usuário. Um manipulador fornece métodos para receber instâncias da classe Message ou Runnable.

O encadeamento pode postar mensagens pelo método sendMessage (Message msg) ou pelo método sendEmptyMessage ().

... mais informações aqui sobre threads etc. (inclui informações dos diferentes mecanismos de encadeamento e sincronização e quando usar o que)

Beachwalker
fonte
Obrigado por reservar um tempo para responder à minha pergunta. Eu amo o blog de Lars Vogel, é muito perspicaz e fácil de seguir. Obrigado!
JRun
2

Quais são as vantagens / razões para usar um manipulador e não um thread?

Um manipulador permite enviar e processar mensagens e Runnableobjetos associados a um encadeamento MessageQueue. Cada Handlerinstância está associada a um único encadeamento e à fila de mensagens desse encadeamento.

Quando você cria um novo Handler, ele é vinculado à fila de encadeamentos / mensagens do encadeamento que o está criando - a partir desse momento, ele envia mensagens e executáveis ​​para essa fila de mensagens e as executa quando saem da fila de mensagens. .

Existem dois usos principais para um manipulador:

  1. Para agendar mensagens e Runnables a serem executados como algum ponto no futuro
  2. Para enfileirar uma ação a ser executada em um segmento diferente do seu.

Se você usa threads java, precisa lidar com algumas coisas sozinho - sincronizando com o thread principal, cancelando um thread etc.

Esse único thread não cria um pool de threads, a menos que você use ThreadPoolExecutorou ExecutorServiceAPI.

(Retirou esta consulta dos seus comentários na resposta do Blackbelt)

Por que não usar um executor? e mesmo se eu quisesse usar um manipulador para fazer isso, como?

Referência: artigo Desempenho de Encadeamentos

Existem certos tipos de trabalho que podem ser reduzidos a tarefas distribuídas altamente paralelas. Com o grande volume de pacotes de trabalho, isso cria AsyncTaske HandlerThreadnão é uma classe apropriada. A natureza de thread único AsyncTasktransformaria todo o trabalho em thread em um sistema linear. O uso da HandlerThreadclasse, por outro lado, exigiria que o programador gerencie manualmente o balanceamento de carga entre um grupo de threads.

ThreadPoolExecutor é uma classe auxiliar para facilitar esse processo. Essa classe gerencia a criação de um grupo de threads, define suas prioridades e gerencia como o trabalho é distribuído entre esses threads. À medida que a carga de trabalho aumenta ou diminui, a classe gira ou destrói mais threads para ajustar a carga de trabalho.

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Você pode consultar este artigo do guia do desenvolvedor sobre create-threadpool para obter mais detalhes.

Dê uma olhada nesta postagem para saber Handlercomo executar várias instâncias Runnable. Nesse caso, todas as Runnabletarefas serão executadas em um único thread.

Android: Brinde em um tópico

Ravindra babu
fonte
1

Handlerpode ser usado em conjunto com Threadpara criar um mecanismo na fila. Você pode usar o handlerpara postar algo noThread Looper

Cinto preto
fonte
Obrigado por reservar um tempo para responder à minha pergunta. Por que não usar um executor? e mesmo se eu quisesse usar um manipulador para fazer isso, como?
JRun
executor é um pouco diferente. Para usá-lo, é necessário estender o thread e, na execução, chame o static.metohd prepare.of da classe Looper. depois que você chamar o loop método estático uma fila é criada e você pode usar uma ordem handlerbin para requestes para a frente e obter resultados de volta
Blackbelt