web-dev-qa-db-fra.com

Quelle est la relation entre Looper, Handler et MessageQueue dans Android?

J'ai vérifié le fonctionnaire Android documentation/guide pour Looper, Handler et MessageQueue. _. Mais je ne pouvais pas l'obtenir. Je suis nouveau sur Android, et très confus avec ces concepts.

93
Blake

Un Looper est une boucle de traitement de message: il lit et traite les éléments d'un MessageQueue . La classe Looper est généralement utilisée conjointement avec un HandlerThread (une sous-classe de Thread).

A Handler est une classe d'utilitaires facilitant l'interaction avec un Looper— principalement en publiant des messages et des objets Runnable dans le MessageQueue. Lorsqu'un Handler est créé, il est lié à un Looper spécifique (et à son thread et à sa file d'attente de messages).

En utilisation typique, vous créez et démarrez un HandlerThread, puis vous créez un objet Handler par lequel d'autres threads peuvent interagir avec l'instance HandlerThread. Le Handler doit être créé lors de l'exécution sur le HandlerThread, bien qu'une fois créé, il n'y ait plus de restriction sur les threads pouvant utiliser les méthodes de planification de Handler (post(Runnable), etc.)

Le fil principal (un fil d'interface utilisateur) dans une application Android est configuré en tant que fil de gestionnaire avant la création de votre instance d'application.

Mis à part la documentation de classe, il y a une bonne discussion de tout cela ici .

P.S. Toutes les classes mentionnées ci-dessus sont dans le package Android.os.

102
Ted Hopp

Tout le monde sait qu'il est illégal de mettre à jour les composants de l'interface utilisateur directement à partir de threads autres que thread principal sous Android. Ce document Android ( Gestion des opérations coûteuses dans le fil de l'interface utilisateur ) suggère les étapes à suivre si vous devez démarrer un fil séparé pour faire du travail coûteux. et mettre à jour l'interface utilisateur une fois l'opération terminée. L'idée est de créer un objet gestionnaire associé à thread principal, et de lui envoyer un exécutable au moment opportun. Ce Runnable sera invoqué sur le thread principal. Ce mécanisme est implémenté avec les classes Looper et Handler .

La classe Looper gère un MessageQueue , qui contient une liste messages . Un caractère important de Looper est qu'il est associé avec le thread dans lequel le Looper est créé. Cette association est conservée pour toujours et ne peut être ni cassée ni modifiée. Notez également qu'un thread ne peut pas être associé à plus de un Looper. Afin de garantir cette association, Looper est stocké dans le stockage local des threads et ne peut pas être créé directement via son constructeur. La seule façon de la créer est d'appeler prepare méthode statique sur Looper. prepare, examine d'abord ThreadLocal du thread en cours pour s'assurer qu'il n'y a pas déjà de Looper associé au thread. Après l'examen, un nouveau Looper est créé et enregistré dans ThreadLocal. Après avoir préparé le Looper, nous pouvons appeler la méthode boucle pour vérifier les nouveaux messages et disposer de Handler pour les traiter.

Comme son nom l'indique, la classe Handler est principalement responsable du traitement (ajout, suppression, envoi) des messages du MessageQueue du thread actuel. Une instance de Handler est également liée à un thread. La liaison entre Handler et Thread est réalisée via Looper et MessageQueue. Un Handler est toujours lié à un Looper, et ensuite lié au thread associé au Looper. Contrairement à Looper, plusieurs instances de gestionnaire peuvent être liées au même thread. Chaque fois que nous appelons post ou une méthode similaire sur le Handler, un nouveau message est ajouté au MessageQueue associé. Le champ cible du message est défini sur l'instance actuelle Handler. Lorsque Looper a reçu ce message, il appelle dispatchMessage sur le champ cible du message, afin que le message soit renvoyé à l'instance du gestionnaire à gérer, mais sur le thread correct. Les relations entre Looper, Handler et MessageQueue sont indiquées ci-dessous:

enter image description here

94
K_Anas

Commençons par le Looper. Vous pouvez comprendre la relation entre Looper, Handler et MessageQueue plus facilement lorsque vous comprenez ce qu'est Looper. Vous pouvez également mieux comprendre ce qu'est Looper dans le contexte de la structure d'interface graphique. Looper est fait pour faire 2 choses.

1) Looper transforme un thread normal , qui se termine lorsque sa méthode run() renvoie, en quelque chose qui tourne continuellement jusqu'à ce que Android app soit en cours d'exécution , ce qui est nécessaire dans le cadre d'une interface graphique (techniquement, il se termine toujours lorsque la méthode run() est renvoyée Mais laissez-moi clarifier ce que je veux dire, ci-dessous).

2) Looper fournit une file d'attente dans laquelle les tâches à effectuer sont mises en file d'attente, ce qui est également nécessaire dans le cadre d'une 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 Android fonctionnent normalement entièrement sur un seul thread, par défaut le " fil principal ". Mais le fil principal n'est pas un fil secret, un fil spécial . C'est juste un fil normal que vous pouvez également créer avec new Thread() code, ce qui signifie qu'il se termine lorsque sa méthode run() retourne! Pensez à l'exemple ci-dessous.

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();
    }
}

Maintenant, appliquons ce principe simple à Android app. Que se passera-t-il si un Android app est exécuté sur un fil normal? Un fil appelé "principal" ou "UI" ou tout ce qui démarre l'application, et dessine toute l'interface utilisateur. Ainsi, le premier écran est affiché pour les utilisateurs. Et maintenant? Le fil principal se termine? Non, il ne devrait pas. Il devrait attendre jusqu'à ce que les utilisateurs fassent quelque chose, non? Mais Mais Comment pouvons-nous obtenir ce comportement? Eh bien, nous pouvons essayer avec Object.wait() ou Thread.sleep(). Par exemple, le thread principal termine son travail initial pour afficher le premier écran, et se met en sommeil. signifie interrompu, lorsqu'un nouveau travail à effectuer est récupéré. Jusqu'ici tout va bien, mais pour le moment nous avons besoin d'une structure de données semblable à une file d'attente pour contenir plusieurs travaux. Pensez au cas où un utilisateur touche l'écran en série, et une tâche prend plus de temps Nous avons donc besoin d’une structure de données pour que les travaux soient exécutés du premier au premier sorti. Vous pouvez également imaginer la mise en œuvre d’un thread toujours en cours d’exécution et de traitement lorsque le processus est arrivé. en utilisant l'interrup Cela 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 que Looper est tout à propos. Le document officiel de la classe Looper indique: "Les threads ne sont associés à aucune boucle de message par défaut", et Looper est une classe "utilisée pour exécuter une boucle de message pour un thread". Maintenant, vous pouvez comprendre ce que cela signifie.

Passons maintenant à 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 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, il devrait y avoir une méthode qui devrait nous permettre de mettre en file d'attente une nouvelle tâche 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) à l'aide de diverses méthodes post(Runnable r). C'est ça. Il s’agit de Looper, Handler et MessageQueue.

Mon dernier mot est, donc Looper est une classe qui est faite pour résoudre un problème qui se produit dans le cadre d'une interface graphique. Mais ce type de besoins peut également se produire dans d'autres situations. En fait, il s’agit d’un motif assez connu pour les applications multi-threads, et vous en apprendrez plus à ce sujet dans "Programmation concurrente en Java" de Doug Lea (Le chapitre 4.1.4 "Thread Worker" serait particulièrement utile). En outre, vous pouvez imaginer que ce type de mécanisme n’est pas unique dans le cadre Android, mais tous les cadres d’interface graphique peuvent nécessiter quelque chose de similaire. Vous pouvez trouver presque le même mécanisme dans Java Cadre Swing.

73
김준호

MessageQueue: il s'agit d'une classe de bas niveau contenant la liste des messages à envoyer par un Looper. Les messages ne sont pas ajoutés directement à un objet MessageQueue, mais plutôt via les objets Handler associés à l'objet Looper. []

Looper: il boucle sur un MessageQueue qui contient les messages à envoyer. La tâche réelle de gestion de la file d'attente est effectuée par le Handler qui est responsable du traitement (ajout, suppression, distribution) des messages dans la file d'attente. [ 2 ]

Handler: il vous permet d'envoyer et de traiter les objets Message et Runnable associés au MessageQueue d'un thread. Chaque instance de gestionnaire est associée à un seul thread et à la file de messages de ce thread. [ 4 ]

Lorsque vous créez un nouveau Handler, il est lié au fil/file de messages du fil qui le crée - à partir de ce moment, , il livrera des messages et des runnables. à cette file d'attente de messages et , exécutez-les lorsqu'ils sortent de la file d'attente de messages .

Veuillez passer par l'image ci-dessous [ 2 ] pour une meilleure compréhension.

enter image description here

25
AnV

MessageQueue, Handler, Looper in Android MessageQueue:

MessageQueue est une boucle de message ou une file de messages qui contient essentiellement une liste de Messages ou de Runnables (ensemble de code exécutable).

En d'autres termes, MessageQueue est une file d'attente comportant des tâches appelées messages qui doivent être traités.

Remarque: Android gère un MessageQueue sur le fil principal.

Looper:

Looper est un opérateur qui sert un MessageQueue pour le thread actuel. Le Looper parcourt la file de messages et envoie les messages aux gestionnaires correspondants à traiter.

Chaque thread ne peut avoir qu'un seul Looper unique, cette contrainte est obtenue en utilisant un concept de stockage ThreadLocal.

Avantages de Looper et de MessageQueue

Il existe certains avantages à utiliser Looper et MessageQueue comme décrit ci-dessous.

· Avec l'utilisation de MessageQueue, l'exécution est séquentielle. Ainsi, en cas de threads simultanés, cela évite les situations de concurrence.

· Normalement, le thread ne peut pas être réutilisé une fois son travail terminé. Toutefois, le thread avec Looper reste actif jusqu’à ce que vous appeliez la méthode quit, vous n’avez donc pas besoin de créer une nouvelle instance chaque fois que vous souhaitez exécuter un travail en arrière-plan.

Gestionnaire:

Un gestionnaire permet de communiquer avec le thread d'interface utilisateur à partir d'un autre thread d'arrière-plan. Ceci est utile dans Android en tant que Android ne permet pas aux autres threads de communiquer directement avec le fil de l'interface utilisateur.

Un gestionnaire vous permet d’envoyer et de traiter les objets Message et Runnable associés au MessageQueue d’un thread. Chaque instance de gestionnaire est associée à un seul thread et à la file de messages de ce thread.

Lorsque vous créez un nouveau gestionnaire, il est lié au thread/à la file d'attente de messages du thread qui le crée - à partir de ce moment, il distribuera les messages et les exécutables à cette file d'attente et les exécutera au fur et à mesure qu'ils sortent de la file d'attente. .

Il y a deux utilisations principales pour un gestionnaire:

(1) Pour programmer les messages et les runnables à exécuter ultérieurement. En d'autres termes, effectuez une action sur le même fil à l'avenir.

(2) Pour mettre en file d'attente une action à effectuer sur un autre thread que le vôtre. En d'autres termes, mettez en file d'attente une action à effectuer sur un autre thread.

4
neeraj kirola