Comprendre le noyau Android : Looper, Handler et HandlerThread

 Comprendre Android Core : Looper, Handler et HandlerThread

Cet article couvre Android Looper, Handler et HandlerThread. Ce sont parmi les blocs de construction d’Android OS.

Dans ma propre expérience, je les ai utilisés dans un contexte très limité jusqu’à récemment. Mon cas d’utilisation consistait à envoyer des tâches au thread principal / ui, principalement pour mettre à jour l’interface utilisateur à partir de n’importe quel autre thread. Les autres aspects de l’opération multithread ont été traités par d’autres moyens tels que ThreadPoolExecutor, IntentService et AsyncTask.

Le MultiThreading et l’exécution de tâches sont d’anciens sujets. Java lui-même a java.util.package simultané et framework Fork / Join pour le faciliter. Plusieurs bibliothèques ont été écrites pour rationaliser les opérations asynchrones. RxJava est la bibliothèque la plus populaire aujourd’hui pour la programmation réactive et la conception d’une application asynchrone.

Alors, pourquoi est-ce que j’écris sur la vieille école?

Looper, Handler, et HandlerThread sont la façon dont Android résout les problèmes de programmation asynchrone. Ils ne sont pas de la vieille école, mais une structure soignée sur laquelle un framework Android complexe est construit.

Pour les nouveaux développeurs, il est fortement recommandé de comprendre les principes qui les sous-tendent et de revoir ce sujet pour en rappeler les détails mineurs.

J’ai également créé un tutoriel vidéo pour ce sujet, et je recommande fortement de le regarder. Cliquez ici pour regarder maintenant.

Cas d’utilisation:

  1. Le thread principal dans Android est construit avec un Looper et Handlers. Donc, la compréhension de celui-ci est essentielle pour créer une interface utilisateur réactive débloquée.
  2. Les développeurs qui écrivent des bibliothèques ne peuvent pas se permettre d’utiliser des bibliothèques tierces en raison de la taille de la bibliothèque. Donc, pour eux, la meilleure option est d’utiliser la ressource disponible existante. Écrire sa propre solution pour cela peut ne pas toujours obtenir ce niveau d’efficacité et d’optimisation.
  3. Le même argument peut également être avancé pour les entreprises/particuliers qui expédient des SDK. Les clients peuvent avoir des implémentations variées, mais tous partageront les API de framework Android communes.
  4. Les comprendre pleinement améliorera la capacité de suivre le SDK Android et les classes de packages en général.

Commençons l’exploration / révision par un questionnaire.

Je m’attends à ce que le lecteur ait la compréhension de base des threads java. Si vous en avez besoin, obtenez un aperçu rapide du thread java et exécutable.

Quel est le problème avec le thread java?

Les threads Java sont à usage unique et meurent après l’exécution de sa méthode run.

Pouvons-nous l’améliorer?

Le Fil est une épée à double tranchant. Nous pouvons accélérer l’exécution en répartissant les tâches entre les threads d’exécution, mais nous pouvons également la ralentir lorsque les threads sont en excès. La création de threads en soi est une surcharge. La meilleure option est donc d’avoir un nombre optimal de threads et de les réutiliser pour l’exécution des tâches.

Modèle de réutilisation des threads:

  1. Le thread est maintenu en vie, dans une boucle via sa méthode run().
  2. La tâche est exécutée en série par ce thread et est maintenue dans une file d’attente (MessageQueue).
  3. Le thread doit être terminé une fois terminé.

Quelle est la façon dont l’Androïde le fait?

Le modèle ci-dessus est implémenté dans Android via Looper, Handler et HandlerThread. Le système peut être visualisé comme un véhicule comme dans la couverture de l’article.

  1. MessageQueue est une file d’attente qui a des tâches appelées messages qui doivent être traitées.
  2. Handler met en file d’attente la tâche dans le MessageQueue en utilisant Looper et les exécute également lorsque la tâche sort du MessageQueue.
  3. Looper est un travailleur qui maintient un thread en vie, parcourt MessageQueue en boucle et envoie des messages au handler correspondant à traiter.
  4. Enfin Thread se termine en appelant la méthode quit() de Looper.

Un thread ne peut avoir qu’un seul boucleur unique et peut avoir de nombreux gestionnaires uniques associés à celui-ci.

Création de Looper et de MessageQueue pour un Thread :

Un thread obtient un Looper et MessageQueue en appelant Looper.prepare() après son exécution. Looper.prepare() identifie le thread appelant, crée un objet Looper et MessageQueue et associe le thread avec eux dans la classe de stockage ThreadLocal. Looper.loop() doit être appelé pour démarrer le boucleur associé. De même, le looper doit être terminé explicitement par looper.quit().

class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; Looper.loop(); } }

Création du gestionnaire pour un Thread :

Un Handler est implicitement associé au thread qui l’instancie via le thread Looper, mais nous pouvons explicitement le lier à un thread en passant le thread looper dans le constructeur du Handler.

handler = new Handler() {@Overridepublic void handleMessage(Message msg) { // process incoming messages here // this will run in the thread, which instantiates it }};

L’envoi de messages au MessageQueue via Handler peut se faire par deux modes:

  1. Message: C’est une classe qui définit diverses méthodes utiles pour traiter les données de message. Pour envoyer un objet, nous définissons la variable obj.
Message msg = new Message();msg.obj = "Ali send message";handler.sendMessage(msg);

Un aperçu détaillé de la classe Message peut être trouvé ici: https://developer.android.com/reference/android/os/Message.html

Runnable: Un runnable peut également être affiché dans le MessageQueue. Ex: publier et exécuter une tâche dans le thread principal.

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() { // this will run in the main thread }});

Dans l’exemple ci-dessus, nous créons un Handler et fournissons Looper associé au thread principal. Cela associe ce gestionnaire au thread principal. Lorsque nous publions le Runnable, il est mis en file d’attente dans le thread principal MessageQueue, puis exécuté dans le thread principal.Le gestionnaire

est capable de manipuler des messages de différentes manières, ce qui peut être trouvé ici: https://developer.android.com/reference/android/os/Handler.html

Créer un propre thread et fournir Lopper et MessageQueue n’est pas la bonne façon de résoudre le problème. Ainsi, Android a fourni HandlerThread (sous-classe de Thread) pour rationaliser le processus. En interne, il fait les mêmes choses que nous avons faites, mais de manière robuste. Donc, utilisez toujours HandlerThread.

L’une des façons de créer le HandlerThread consiste à le sous-classer et la plupart du temps, vous utiliserez cette méthode.

private class MyHandlerThread extends HandlerThread { Handler handler; public MyHandlerThread(String name) { super(name); } @Override protected void onLooperPrepared() { handler = new Handler(getLooper()) { @Override public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; }}

Remarque : Nous avons instancié le gestionnaire lorsque le onLooperPrepared() est appelé. Donc, ce Handler peut être associé à ce Looper.

  1. Looper n’est préparé qu’après l’appel de start() de HandlerThread, c’est-à-dire après l’exécution du thread.
  2. Un Handler peut être associé à un HandlerThread, seulement après sa préparation Looper.

Autre moyen de créer le HandlerThread:

HandlerThread handlerThread = new HandlerThread("MyHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());

Note: HandlerThread doit appeler myHandlerThread.quit() pour libérer les ressources et arrêter l’exécution du thread.

Je suggère de pratiquer les codes ci-dessus, afin que vous puissiez saisir leurs petits détails.

J’ai créé un exemple de projet pour la simulation de bureau de poste. Bureau de Poste est construit sur HandlerThread et les clients communiquent avec l’aide du Bureau de Poste. Une classe de simulateur crée peu de Bots clients et délègue leur communication à MainActivity, qui la rend dans un flux en direct.

Le lien vers cet exemple

J’ai également créé un tutoriel vidéo pour ce sujet, et je recommande fortement de le regarder. Cliquez ici pour regarder maintenant.

Aussi, devenons amis sur Twitter, Linkedin, Github et Facebook.

Apprendre est un voyage, apprenons ensemble !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.