Qual a diferença entre Handler e Thread

Primeiro, um conceito básico (se você já sabe essa parte, pode pular para o último parágrafo):

Existe o thread principal, também chamado de UI thread, cuja função central é executar operações de UI (interface de usuário), isto é, que atualizam a tela do aplicativo, como exibir textos, imagens, etc. Este thread não deve ser sobrecarregado com operações não relacionadas a UI que sejam muito pesadas, sob pena de causar os famosos ANRs, isto é, avisos de atraso na atualização de tela que causam travamentos na responsividade do aplicativo.

E há os threads secundários (qualquer thread que não seja o principal), estes sim adequados para operações mais pesadas que não sejam de UI, mas que não têm acesso direto à fila de execução do thread principal e portanto não é possível chamar operações de atualização da tela diretamente por eles; são necessários Handlers para isso, que são objetos que “postam” uma operação de UI na fila de operações a serem executadas pelo thread principal (a isso se chama postar uma “mensagem” ou Runnable no thread principal). A diferença entre uma mensagem (classe Message) e um Runnable é mínima; ambos são trechos de código executável, sendo que Message armazena uma referência para um objeto que pode ser importante para o código sendo executado (muitas vezes isso não é necessário, bastando passar apenas um Runnable para o thread através do método Handler.post(Runnable)).

No seu caso, você tem um thread secundário executando operações não-UI (as chamadas a sleep()) e que de tempos em tempos precisa comunicar ao thread principal que o componente de UI ProgressBar precisa ser atualizado (essa operação de UI seria a chamada a ProgressBar.setProgress()). Como já dito o seu thread secundário não tem acesso direto à fila de execução do thread principal e para postar uma “mensagem” para o thread principal executar ele deveria usar um Handler. O código ficaria por exemplo assim:

final Handler handler = new Handler(Looper.getMainLooper());
final int tempoDeEspera = 500;
int i;

new Thread(new Runnable() {
    @Override
    public void run() {
        for (i = 0; i < 5; i++) {
            SystemClock.sleep(tempoDeEspera);
            handler.post(new Runnable() {
                @Override
                public void run() {
                    progressBar.setProgress(i);
                }
            });
        }
    }).start();

Obs.: Não testei para ver se esse código compila, mas ele serve para ilustrar o conceito de Handler e a diferença entre operações de UI e não-UI e os respectivos threads que as executam.

Exemplos de operações pesadas que exigem processamento e portanto devem ser executadas em um thread separado: operações de I/O, como acesso à rede (requisições HTTP em geral, como acesso a URLs), escrita de arquivos e no banco de dados SQLite, processamentos matemáticos pesados, etc.

Uma complementação: no seu caso funcionou sem o Handler porque a operação ProgressBar.setProgress() executa um post() internamente (a ProgressBar herda esse método de View), que põe a atualização da ProgressBar na fila de execução do thread principal. Mas nem todos os componentes de UI fazem isso, de forma que o Handler continua sendo útil em muitos casos.

Escrito por piovezan

Deixe uma resposta