J'ai vérifié la documentation / guide officiel Android pour Looper
, Handler
et MessageQueue
. Mais je n'ai pas pu l'obtenir. Je suis nouveau sur Android et j'ai été très confus avec ces concepts.
J'ai vérifié la documentation / guide officiel Android pour Looper
, Handler
et MessageQueue
. Mais je n'ai pas pu l'obtenir. Je suis nouveau sur Android et j'ai été très confus avec ces concepts.
A Looper
est une boucle de gestion de messages: il lit et traite les éléments d'un fichier MessageQueue
. La Looper
classe est généralement utilisée en conjonction avec une HandlerThread
(une sous-classe de Thread
).
A Handler
est une classe utilitaire qui facilite l'interaction avec un - Looper
principalement en publiant des messages et des Runnable
objets dans le thread MessageQueue
. Lorsqu'une Handler
est créée, elle est liée à un Looper
thread spécifique (et associé à une file de discussion et de messages).
Dans une utilisation classique, vous créez et démarrez un HandlerThread
, puis créez un Handler
objet (ou des objets) par lesquels d'autres threads peuvent interagir avec l' HandlerThread
instance. Le Handler
doit être créé lors de l'exécution sur le HandlerThread
, bien qu'une fois créé, il n'y ait aucune restriction sur les threads pouvant utiliser les Handler
méthodes de planification de s ( post(Runnable)
, etc.)
Le thread principal (aka thread UI) dans une application Android est configuré en tant que thread de gestionnaire avant la création de votre instance d'application.
En plus des documents de classe, il y a une belle discussion sur tout cela ici .
PS Toutes les classes mentionnées ci-dessus sont dans le package android.os
.
MessageQueue
Android pour indiquer que aMessageQueue
est une " classe de bas niveau contenant la liste des messages à envoyer par aLooper
. "Il est bien connu qu'il est illégal de mettre à jour les composants de l'interface utilisateur directement à partir de threads autres que le thread principal dans Android. Ce document Android ( Gestion des opérations coûteuses dans le thread d'interface utilisateur ) suggère les étapes à suivre si nous devons démarrer un thread séparé pour effectuer un travail coûteux et mettre à jour l'interface utilisateur une fois terminé. L'idée est de créer un objet Handler associé au thread principal et d'y publier un Runnable au moment opportun. Cela
Runnable
sera appelé sur le thread principal . Ce mécanisme est implémenté avec les classes Looper et Handler .La
Looper
classe gère un MessageQueue , qui contient une liste de messages . Un caractère important de Looper est qu'il est associé au thread dans lequel leLooper
est créé . Cette association est conservée pour toujours et ne peut être ni rompue ni modifiée. Notez également qu'un fil ne peut pas être associé à plus d' unLooper
. Afin de garantir cette association,Looper
est stocké dans le stockage local du thread, et il ne peut pas être créé directement via son constructeur. La seule façon de le créer est d'appeler la méthode prepare static onLooper
. préparer la méthode examine d'abord ThreadLocaldu thread actuel pour vous assurer qu'il n'y a pas déjà un Looper associé au thread. Après l'examen, un nouveauLooper
est créé et enregistré dansThreadLocal
. Après avoir préparé leLooper
, nous pouvons appeler la méthode de boucle dessus pour vérifier les nouveaux messages et lesHandler
traiter.Comme son nom l'indique, la
Handler
classe est principalement chargée de gérer (ajouter, supprimer, distribuer) les messages des threads actuelsMessageQueue
. UneHandler
instance est également liée à un thread. La liaison entre Handler et Thread est réalisée viaLooper
etMessageQueue
. AHandler
est toujours lié à aLooper
, puis lié au thread associé auLooper
. Contrairement àLooper
, plusieurs instances de Handler peuvent être liées au même thread. Chaque fois que nous appelons post ou toute autre méthode similaire sur leHandler
, un nouveau message est ajouté au fichier associéMessageQueue
. Le champ cible du message est défini sur l'Handler
instance actuelle . Quand leLooper
a reçu ce message, il invoque dispatchMessage sur le champ cible du message, afin que le message soit renvoyé vers l'instance Handler à traiter, mais sur le thread correct. Les relations entreLooper
,Handler
etMessageQueue
est présenté ci - dessous:la source
Commençons par le Looper. Vous pouvez comprendre plus facilement la relation entre Looper, Handler et MessageQueue lorsque vous comprenez ce qu'est Looper. Vous pouvez également mieux comprendre ce qu'est Looper dans le contexte du framework GUI. Looper est fait pour faire 2 choses.
1) Looper transforme un thread normal , qui se termine lorsque sa
run()
méthode retourne, en quelque chose qui s'exécute en continu jusqu'à ce que l'application Android soit en cours d'exécution , ce qui est nécessaire dans le cadre de l'interface graphique (techniquement, il se termine toujours lorsque larun()
méthode revient. Mais laissez-moi clarifier ce que je veux dire, au dessous de).2) Looper fournit une file d'attente dans laquelle les travaux à effectuer sont mis en file d'attente, ce qui est également nécessaire dans le cadre de l'interface graphique.
Comme vous le savez peut-être, lorsqu'une application est lancée, le système crée un thread d'exécution pour l'application, appelé «main», et les applications Android fonctionnent normalement entièrement sur un seul thread par défaut le «thread principal». Mais le fil principal n'est pas un fil spécial et secret . C'est juste un thread normal que vous pouvez également créer avec du
new Thread()
code, ce qui signifie qu'il se termine lorsque sarun()
méthode revient! Pensez à l'exemple ci-dessous.Maintenant, appliquons ce principe simple à l'application Android. Que se passerait-il si une application Android était exécutée sur un thread normal? Un thread appelé "main" ou "UI" ou quoi que ce soit démarre l'application, et dessine toute l'interface utilisateur. Ainsi, le premier écran est affiché aux utilisateurs. Et maintenant? Le thread principal se termine? Non, ça ne devrait pas. Il devrait attendre que les utilisateurs fassent quelque chose, non? Mais comment parvenir à ce comportement? Eh bien, nous pouvons essayer avec
Object.wait()
ouThread.sleep()
. Par exemple, le thread principal termine son travail initial pour afficher le premier écran et se met en veille. Il se réveille, ce qui signifie interrompu, lorsqu'un nouveau travail à faire est récupéré. Jusqu'ici tout va bien, mais pour le moment, nous avons besoin d'une structure de données en forme de file d'attente pour contenir plusieurs tâches. Pensez à un cas où un utilisateur touche l'écran en série et qu'une tâche prend plus de temps à se terminer. Nous avons donc besoin d'une structure de données pour conserver les tâches à effectuer de la manière premier entré, premier sorti. De plus, vous pouvez imaginer que l'implémentation d'un thread toujours en cours d'exécution et de traitement à l'arrivée à l'aide d'interruption n'est pas facile et conduit à un code complexe et souvent impossible à maintenir. Nous préférerions créer un nouveau mécanisme à cette fin, et c'est ce qu'est Looper . Le document officiel de la classe Looperdit, "Les threads par défaut n'ont pas de boucle de message associée", et Looper est une classe "utilisée pour exécuter une boucle de message pour un thread". Vous pouvez maintenant comprendre ce que cela signifie.Passons à Handler et MessageQueue. Tout d'abord, MessageQueue est la file d'attente que j'ai mentionnée ci-dessus. Il réside dans un Looper, et c'est tout. Vous pouvez le vérifier avec le code source de la classe Looper . La classe Looper a une variable membre de MessageQueue.
Alors, qu'est-ce que Handler? S'il y a une file d'attente, alors il devrait y avoir une méthode qui devrait nous permettre de mettre une nouvelle tâche en file d'attente dans la file d'attente, non? C'est ce que fait Handler. Nous pouvons mettre en file d'attente une nouvelle tâche dans une file d'attente (MessageQueue) en utilisant diverses
post(Runnable r)
méthodes. C'est tout. Tout cela concerne Looper, Handler et MessageQueue.Mon dernier mot est, donc fondamentalement, Looper est une classe conçue pour résoudre un problème qui se produit dans le cadre de l'interface graphique. Mais ce type de besoins peut également se produire dans d'autres situations. En fait, c'est un modèle assez célèbre pour les applications multi threads, et vous pouvez en apprendre plus à ce sujet dans "Programmation simultanée en Java" par Doug Lea (en particulier, le chapitre 4.1.4 "Worker Threads" serait utile). En outre, vous pouvez imaginer que ce type de mécanisme n'est pas unique dans le cadre Android, mais tous les cadres GUI peuvent nécessiter un peu similaire à celui-ci. Vous pouvez trouver presque le même mécanisme dans le framework Java Swing.
la source
MessageQueue
: C'est une classe de bas niveau contenant la liste des messages à envoyer par unLooper
. Les messages ne sont pas ajoutés directement à unMessageQueue
, mais plutôt via desHandler
objets associés àLooper
. [ 3 ]Looper
: Il boucle sur unMessageQueue
qui contient les messages à envoyer. La tâche réelle de gestion de la file d'attente est effectuée par leHandler
qui est chargé de gérer (ajouter, supprimer, distribuer) les messages dans la file d'attente de messages. [ 2 ]Handler
: Il vous permet d'envoyer et de processusMessage
et desRunnable
objets associés à un fil deMessageQueue
. Chaque instance de gestionnaire est associée à un seul thread et à la file d'attente de messages de ce thread. [ 4 ]Lorsque vous créez un nouveau
Handler
, il est lié au thread / file d'attente de messages du thread qui le crée - à partir de ce moment, il remettra les messages et les exécutables à cette file d'attente de messages et les exécutera lorsqu'ils sortent de la file d'attente de messages .Veuillez consulter l'image ci-dessous [ 2 ] pour une meilleure compréhension.
la source
Étendre la réponse, par @K_Anas, avec un exemple, comme indiqué
par exemple, si vous essayez de mettre à jour l'interface utilisateur à l'aide de Thread.
votre application plantera avec exception.
en d'autres termes, vous devez utiliser
Handler
qui garde la référence à la tâcheMainLooper
ieMain Thread
ouUI Thread
et passez en tant queRunnable
.la source