Respostas:
A Looperé um loop de tratamento de mensagens: ele lê e processa itens de a MessageQueue. A Looperclasse é geralmente usada em conjunto com a HandlerThread(uma subclasse de Thread).
A Handleré uma classe de utilitário que facilita a interação com um - Looperprincipalmente postando mensagens e Runnableobjetos no thread MessageQueue. Quando um Handleré criado, ele é vinculado a um específico Looper(e thread associado e fila de mensagens).
No uso típico, você cria e inicia um e HandlerThread, em seguida, cria um Handlerobjeto (ou objetos) pelo qual outros threads podem interagir com a HandlerThreadinstância. O Handlerdeve ser criado durante a execução no HandlerThread, embora uma vez criado, não haja nenhuma restrição sobre quais threads podem usar os Handlermétodos de agendamento de ( post(Runnable), etc.)
O thread principal (também conhecido como thread de interface do usuário) em um aplicativo Android é configurado como um thread de manipulador antes da criação da instância do aplicativo.
Além da documentação da aula, há uma boa discussão sobre tudo isso aqui .
PS Todas as classes mencionadas acima estão no pacote android.os.
MessageQueue Android documenta que a MessageQueueé uma " classe de baixo nível que contém a lista de mensagens a serem despachadas por a Looper. "
É amplamente conhecido que é ilegal atualizar componentes da IU diretamente de threads diferentes do thread principal no Android. Este documento android ( Handling Expensive Operations in the UI Thread ) sugere as etapas a seguir se precisarmos iniciar um thread separado para fazer algum trabalho caro e atualizar a IU depois de concluído. A ideia é criar um objeto Handler associado ao thread principal e postar um Runnable nele no momento apropriado. Isso Runnableserá invocado no thread principal . Este mecanismo é implementado com as classes Looper e Handler .
A Looperclasse mantém um MessageQueue , que contém uma lista de mensagens . Um caractere importante do Looper é que ele está associado ao segmento no qual o Looperé criado . Esta associação é mantida para sempre e não pode ser quebrada nem alterada. Observe também que um tópico não pode ser associado a mais de um Looper. Para garantir essa associação, ele Looperé armazenado no armazenamento local do segmento e não pode ser criado por meio de seu construtor diretamente. A única maneira de criá-lo é chamar o método estático prepare on Looper. método de preparação examina primeiro ThreadLocaldo thread atual para ter certeza de que já não existe um Looper associado ao thread. Após o exame, um novo Looperé criado e salvo no ThreadLocal. Tendo preparado o Looper, podemos chamar o método de loop nele para verificar se há novas mensagens e ter Handlerque lidar com elas.
Como o nome indica, a Handlerclasse é principalmente responsável por manipular (adicionar, remover, despachar) mensagens do thread atual MessageQueue. Uma Handlerinstância também está ligada a um thread. A ligação entre Handler e Thread é realizada por meio de Loopere MessageQueue. A Handlerestá sempre associado a a Loopere, subsequentemente, ao thread associado a Looper. Ao contrário Looper, várias instâncias de Handler podem ser vinculadas ao mesmo thread. Sempre que chamamos post ou quaisquer métodos semelhantes no Handler, uma nova mensagem é adicionada ao associado MessageQueue. O campo de destino da mensagem é definido para a Handlerinstância atual . Quando oLooperrecebeu essa mensagem, ele invoca dispatchMessage no campo de destino da mensagem, de modo que a mensagem seja roteada de volta para a instância Handler a ser tratada, mas no encadeamento correto. As relações entre Looper, Handlere MessageQueueé mostrada abaixo:

Vamos começar com o Looper. Você pode entender a relação entre Looper, Handler e MessageQueue mais facilmente quando entender o que é Looper. Além disso, você pode entender melhor o que é Looper no contexto da estrutura da GUI. Looper é feito para fazer 2 coisas.
1) Looper transforma um thread normal , que termina quando seu run()método retorna, em algo que é executado continuamente até que o aplicativo Android seja executado , o que é necessário na estrutura da GUI (Tecnicamente, ele ainda termina quando o run()método retorna. Mas deixe-me esclarecer o que quero dizer, abaixo).
2) O Looper fornece uma fila onde os trabalhos a serem realizados são enfileirados, o que também é necessário na estrutura da GUI.
Como você deve saber, quando um aplicativo é iniciado, o sistema cria um thread de execução para o aplicativo, chamado “principal”, e os aplicativos Android normalmente são executados inteiramente em um único thread por padrão, o “thread principal”. Mas o tópico principal não é um tópico especial secreto . É apenas um thread normal que você também pode criar com o new Thread()código, o que significa que ele termina quando o run()método retorna! Pense no exemplo abaixo.
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
Agora, vamos aplicar este princípio simples ao aplicativo Android. O que aconteceria se um aplicativo Android fosse executado em uma thread normal? Um thread chamado "principal" ou "UI" ou o que quer que inicie o aplicativo e desenhe toda a UI. Assim, a primeira tela é exibida aos usuários. E agora? O tópico principal termina? Não, não deveria. Deve esperar até que os usuários façam algo, certo? Mas como podemos alcançar esse comportamento? Bem, podemos tentar com Object.wait()ouThread.sleep(). Por exemplo, o thread principal termina seu trabalho inicial para exibir a primeira tela e adormece. Ele acorda, o que significa interrompido, quando uma nova tarefa a ser feita é buscada. Até aqui tudo bem, mas neste momento precisamos de uma estrutura de dados em forma de fila para armazenar vários trabalhos. Pense em um caso em que um usuário toca a tela em série e uma tarefa leva mais tempo para ser concluída. Portanto, precisamos ter uma estrutura de dados para manter as tarefas a serem executadas da maneira primeiro a entrar, primeiro a sair. Além disso, você pode imaginar, implementar um thread sempre em execução e processar o trabalho quando chegado usando interrupção não é fácil e leva a um código complexo e muitas vezes impossível de manter. Preferimos criar um novo mecanismo para esse propósito, e é disso que se trata o Looper . O documento oficial da classe Looperdiz, "Threads por padrão não têm um loop de mensagem associado a eles", e Looper é uma classe "usada para executar um loop de mensagem para um thread". Agora você pode entender o que isso significa.
Vamos passar para Handler e MessageQueue. Primeiro, MessageQueue é a fila que mencionei acima. Ele reside dentro de um Looper, e é isso. Você pode verificar isso com o código-fonte da classe Looper . A classe Looper tem uma variável de membro MessageQueue.
Então, o que é Handler? Se houver uma fila, deve haver um método que nos permita enfileirar uma nova tarefa na fila, certo? É isso que Handler faz. Podemos enfileirar uma nova tarefa em uma fila (MessageQueue) usando vários post(Runnable r)métodos. É isso aí. Isso é tudo sobre Looper, Handler e MessageQueue.
Minha última palavra é, então, basicamente, Looper é uma classe feita para resolver um problema que ocorre no framework GUI. Mas esse tipo de necessidade também pode acontecer em outras situações. Na verdade, é um padrão bastante famoso para aplicação de multithreads, e você pode aprender mais sobre ele em "Programação simultânea em Java" por Doug Lea (especialmente, o capítulo 4.1.4 "Threads de trabalho" seria útil). Além disso, você pode imaginar que esse tipo de mecanismo não é único no framework Android, mas todos os frameworks GUI podem precisar de algo semelhante a este. Você pode encontrar quase o mesmo mecanismo na estrutura Java Swing.
MessageQueue: É uma classe de baixo nível que contém a lista de mensagens a serem despachadas por a Looper. As mensagens não são adicionadas diretamente a a MessageQueue, mas sim por meio de Handlerobjetos associados a Looper. [ 3 ]
Looper: Faz um loop em um MessageQueueque contém as mensagens a serem despachadas. A tarefa real de gerenciamento da fila é feita pelo Handlerresponsável por lidar (adicionar, remover, despachar) mensagens na fila de mensagens. [ 2 ]
Handler: Permite enviar e processar Messagee Runnableobjetos associados a um thread MessageQueue. Cada instância de Handler está associada a um único thread e à fila de mensagens desse thread. [ 4 ]
Quando você cria um novo Handler, ele é vinculado ao thread / fila de mensagens do thread que o está criando - desse ponto em diante, ele entregará mensagens e executáveis para essa fila de mensagens e os executará à medida que saem da fila de mensagens .
Observe a imagem abaixo [ 2 ] para melhor compreensão.
Estendendo a resposta, por @K_Anas, com um exemplo, Como afirmou
É amplamente conhecido que é ilegal atualizar componentes da IU diretamente de threads diferentes do thread principal no Android.
por exemplo, se você tentar atualizar a IU usando Thread.
int count = 0;
new Thread(new Runnable(){
@Override
public void run() {
try {
while(true) {
sleep(1000);
count++;
textView.setText(String.valueOf(count));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
).start();
seu aplicativo irá travar com exceção.
android.view.ViewRoot $ CalledFromWrongThreadException: apenas o encadeamento original que criou uma hierarquia de visualização pode tocar suas visualizações.
em outras palavras, você precisa usar o Handlerque mantém a referência à tarefa MainLooper ie Main Threadou UI Threade pass como Runnable.
Handler handler = new Handler(getApplicationContext().getMainLooper);
int count = 0;
new Thread(new Runnable(){
@Override
public void run() {
try {
while(true) {
sleep(1000);
count++;
handler.post(new Runnable() {
@Override
public void run() {
textView.setText(String.valueOf(count));
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
).start() ;