Fui verificar a documentação / guia oficial Android para Looper
, Handler
e MessageQueue
. Mas eu não consegui entender. Eu sou novo no Android e fiquei muito confuso com esses conceitos.
fonte
Fui verificar a documentação / guia oficial Android para Looper
, Handler
e MessageQueue
. Mas eu não consegui entender. Eu sou novo no Android e fiquei muito confuso com esses conceitos.
A Looper
é um loop de tratamento de mensagens: ele lê e processa itens de a MessageQueue
. A Looper
classe é 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 - Looper
principalmente postando mensagens e Runnable
objetos 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 Handler
objeto (ou objetos) pelo qual outros threads podem interagir com a HandlerThread
instância. O Handler
deve ser criado durante a execução no HandlerThread
, embora uma vez criado, não haja nenhuma restrição sobre quais threads podem usar os Handler
mé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 aMessageQueue
é uma " classe de baixo nível que contém a lista de mensagens a serem despachadas por aLooper
. "É 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
Runnable
será invocado no thread principal . Este mecanismo é implementado com as classes Looper e Handler .A
Looper
classe mantém um MessageQueue , que contém uma lista de mensagens . Um caractere importante do Looper é que ele está associado ao segmento no qual oLooper
é 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 umLooper
. Para garantir essa associação, eleLooper
é 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 onLooper
. 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 novoLooper
é criado e salvo noThreadLocal
. Tendo preparado oLooper
, podemos chamar o método de loop nele para verificar se há novas mensagens e terHandler
que lidar com elas.Como o nome indica, a
Handler
classe é principalmente responsável por manipular (adicionar, remover, despachar) mensagens do thread atualMessageQueue
. UmaHandler
instância também está ligada a um thread. A ligação entre Handler e Thread é realizada por meio deLooper
eMessageQueue
. AHandler
está sempre associado a aLooper
e, subsequentemente, ao thread associado aLooper
. Ao contrárioLooper
, várias instâncias de Handler podem ser vinculadas ao mesmo thread. Sempre que chamamos post ou quaisquer métodos semelhantes noHandler
, uma nova mensagem é adicionada ao associadoMessageQueue
. O campo de destino da mensagem é definido para aHandler
instância atual . Quando oLooper
recebeu 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 entreLooper
,Handler
eMessageQueue
é mostrada abaixo:fonte
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 orun()
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 orun()
método retorna! Pense no exemplo abaixo.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.
fonte
MessageQueue
: É uma classe de baixo nível que contém a lista de mensagens a serem despachadas por aLooper
. As mensagens não são adicionadas diretamente a aMessageQueue
, mas sim por meio deHandler
objetos associados aLooper
. [ 3 ]Looper
: Faz um loop em umMessageQueue
que contém as mensagens a serem despachadas. A tarefa real de gerenciamento da fila é feita peloHandler
responsável por lidar (adicionar, remover, despachar) mensagens na fila de mensagens. [ 2 ]Handler
: Permite enviar e processarMessage
eRunnable
objetos associados a um threadMessageQueue
. 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.
fonte
Estendendo a resposta, por @K_Anas, com um exemplo, Como afirmou
por exemplo, se você tentar atualizar a IU usando Thread.
seu aplicativo irá travar com exceção.
em outras palavras, você precisa usar o
Handler
que mantém a referência à tarefaMainLooper
ieMain Thread
ouUI Thread
e pass comoRunnable
.fonte