Tous ceux qui essaient de développement sur Android découvrent l’importance de la simultanéité. La seule façon de créer une application réactive est de laisser le fil de l'interface utilisateur aussi libre que possible, en laissant tout le travail difficile être effectué de manière asynchrone par les fils d'arrière-plan..
En raison de la conception d’Android, la gestion des threads en utilisant uniquement le java.lang.thread
et java.util.concurrent
les colis pourraient être très difficiles. L'utilisation des packages de threads de bas niveau avec Android signifie que vous devez vous soucier de la synchronisation complexe pour éviter les conditions de concurrence. Heureusement, les employés de Google ont travaillé d'arrache-pied et ont mis au point d'excellents outils pour faciliter notre travail: AsyncTask
, IntentService
, Chargeur
, AsyncQueryHandler
et CursorLoader
sont tous utiles, ainsi que les classes HaMeR Gestionnaire
, Message
, et Runnable
. Vous avez le choix entre plusieurs options intéressantes, chacune avec ses avantages et ses inconvénients..
On a beaucoup parlé de la AsyncTask
objet, et beaucoup de gens l'utilisent comme un balle en argent solution de simultanéité sur Android. Il est extrêmement utile pour les opérations courtes, facile à mettre en œuvre et probablement l’approche la plus populaire pour la concurrence sur Android. Si vous voulez en savoir plus sur AsyncTask
, consultez les articles Envato Tuts suivants.
toutefois, AsyncTask
ne devrait pas être le seul outil sur votre ceinture à outils.
Pour les opérations de longue durée, pour des problèmes de simultanéité complexes ou pour gagner en efficacité dans certaines situations, vous devez choisir une autre solution. Si vous avez besoin de plus de flexibilité ou d'efficacité que AsyncTask
fournit, vous pouvez utiliser le HaMeR (Gestionnaire
, Message
Et Runnable
) cadre.Dans ce tutoriel, nous allons explorer le framework HaMeR, l'un des modèles de concurrence les plus puissants disponibles sur Android, et découvrirons quand et comment l'utiliser. Dans un tutoriel de suivi, je vais vous montrer comment coder une application pour tester certaines possibilités de HaMeR..
La section suivante présentera l’importance des threads d’arrière-plan pour le système Android. Si vous connaissez ce concept, n'hésitez pas à l'ignorer et à passer directement à la discussion du cadre HaMeR dans la section 3..
Lors du démarrage d'une application Android, le premier thread généré par son processus est le thread principal, également appelé thread d'interface utilisateur, qui est responsable de la gestion de toute la logique de l'interface utilisateur. C'est le fil le plus important d'une application. Il est responsable de la gestion de toutes les interactions de l'utilisateur et de la "liaison" entre les pièces mobiles de l'application. Android prend cela très au sérieux et si votre thread d'interface utilisateur est bloqué sur une tâche pendant plus de quelques secondes, l'application se bloque..
[Le fil de l'interface utilisateur] est très important car il est chargé de la distribution des événements aux widgets d'interface utilisateur appropriés, y compris les événements de dessin. C’est également le fil dans lequel votre application interagit avec les composants de la boîte à outils de l’UI Android (composants de laandroid.widget
etandroid.view
paquets). En tant que tel, le thread principal est également parfois appelé le thread d'interface utilisateur. - Processus et threads, Guide du développeur Android
Le problème est que presque tout le code d'une application Android sera exécuté par défaut sur le thread d'interface utilisateur. Étant donné que les tâches sur un fil sont effectuées de manière séquentielle, cela signifie que votre interface utilisateur peut se figer, devenant insensible pendant le traitement d'un autre travail..
Les tâches de longue durée appelées sur l'interface utilisateur seront probablement fatales pour votre application et une boîte de dialogue ANR (Application non répondante) apparaîtra. Même les petites tâches peuvent compromettre l'expérience utilisateur. Par conséquent, la bonne approche consiste à supprimer le plus de travail possible du thread d'interface utilisateur à l'aide de threads d'arrière-plan. Comme indiqué précédemment, il existe de nombreuses façons de résoudre ce problème et nous allons explorer le cadre HaMeR, l'une des solutions clés fournies par Android pour remédier à cette situation..
Le framework HaMeR permet aux threads d’arrière-plan d’envoyer des messages ou de publier des runnables au thread d’UI et à tout autre thread. MessageQueue
via des handlers. HaMeR fait référence à Gestionnaire
, Message
, Et Runnable
. Il y a aussi quelques autres classes importantes qui travaillent avec le HaMeR: Looper
et MessageQueue
. Ensemble, ces objets sont chargés de faciliter la gestion des threads sur Android, d'assurer la synchronisation et de fournir des méthodes simples permettant aux threads d'arrière-plan de communiquer avec l'interface utilisateur et avec d'autres threads..
Voici comment les classes du framework HaMeR s'emboîtent.
Looper
exécute une boucle de message sur un fil en utilisant le MessageQueue
.MessageQueue
contient une liste de messages à envoyer par le Looper
.Gestionnaire
permet l'envoi et le traitement de Message
et Runnable
au MessageQueue
. Il peut être utilisé pour envoyer et traiter des messages entre les threads.Message
contient une description et des données pouvant être envoyées à un gestionnaire.Runnable
représente une tâche à exécuter.Avec le framework HaMeR, les threads peuvent envoyer des messages ou publier des objets exécutables soit pour eux-mêmes, soit pour le thread d'interface utilisateur. HaMeR favorise également les interactions de fil de fond via Gestionnaire
.
Gestionnaire
est le cheval de bataille HaMeR. C'est responsable de l'envoi Message
(message de données) et post Runnable
(message de tâche) objets à la MessageQueue
associé à un Fil
. Après avoir livré les tâches à la file d’attente, le gestionnaire reçoit les objets de la Looper
et traite les messages au moment opportun en utilisant le Gestionnaire
associé avec.
UNE Gestionnaire
peut être utilisé pour envoyer ou poster Message
et Runnable
objets entre les threads, tant que ces threads partagent le même processus. Sinon, il sera nécessaire de créer une communication IPC (Inter Process Communication), une méthodologie qui dépasse le cadre de ce tutoriel..
UNE Gestionnaire
doit toujours être associé à un Looper
, et cette connexion doit être faite pendant son instanciation. Si vous ne fournissez pas un Looper
au Gestionnaire
, il sera lié au courant Fil
de Looper
.
// Handler utilise le handler actuel du Looper Handler = new Handler (); // Handler utilise le Looper fournit Handler handler = new Handler (Looper);
Gardez à l'esprit qu'un Gestionnaire
est toujours associé à un Looper
, et cette connexion est permanente et ne peut pas être changée une fois établie. Cependant, un Looper
Le fil peut avoir des associations avec plusieurs Gestionnaire
s. Il est également important de noter qu’un Looper
doit être actif avant son association avec un Gestionnaire
.
Le travail en coopération entre Looper
et MessageQueue
dans un thread Java crée une boucle de tâches traitées séquentiellement. Une telle boucle gardera le fil en vie pendant qu'il attend de recevoir plus de tâches. Un fil ne peut avoir qu'un seul Looper
et une MessageQueue
associé avec; Cependant, il peut y avoir plusieurs gestionnaires pour chaque thread. Les gestionnaires sont responsables du traitement des tâches de la file d'attente et chaque tâche sait quel gestionnaire est responsable de son traitement..
L’UI ou le fil principal est le seul type de fil qui, par défaut, possède déjà un Gestionnaire
, une Looper
, et un MessageQueue
. D'autres threads doivent être préparés avec ces objets avant de pouvoir fonctionner avec le framework HaMeR. Nous devons d’abord créer un Looper
qui comprend déjà un MessageQueue
et attachez-le au fil. Vous pouvez le faire avec une sous-classe de Fil
, comme suit.
// Préparation d'un thread pour la classe HaMeR LooperThread extend Thread public Handler mHandler; public void run () // ajouter et préparer le Looper Looper.prepare (); // l'instance du gestionnaire sera associée à la boucle d'exécution du thread mHandler = new Handler () public void handleMessage (Message msg) // traite les messages entrants ici; // Lancement de la boucle de messages en utilisant le Looper Looper.loop ();
Cependant, il est plus simple d'utiliser une classe d'assistance appelée HandlerThread
, qui a un Looper
et un MessageQueue
construit en Java Fil
et est prêt à recevoir un gestionnaire.
// La classe HandlerThread inclut une classe publique Looper en fonctionnement. HamerThread extend HandlerThread // vous devez simplement ajouter le gestionnaire Handler private Handler handler; public HamerThread (nom de chaîne) super (nom);
le Runnable
est une interface Java qui a de nombreux usages. On pourrait le comprendre comme une tâche unique à exécuter sur Fil
. Il a une seule méthode qui doit être implémentée, Runnable.run ()
, pour effectuer la tâche.
// Déclaration d'une runnable exécutable r = new Runnable () @Override public void run () // la tâche est lancée ici;
Il y a plusieurs options pour poster un Runnable
sur un Gestionnaire
.
Handler.post (Runnable r)
: ajouter le Runnable
au MessageQueue
.Handler.postAtFrontOfQueue (Runnable r)
: ajouter le Runnable
à l'avant de la MessageQueue
.Gestionnaire.postAtTime (Runnable r, long timeMillis)
: ajouter le Runnable
sur le MessageQueue
être appelé à une heure précise.Gestionnaire.postDelayed (Runnable r, long delay)
: ajouter le Runnable
dans la file d'attente à appeler après un laps de temps déterminé.// publiant un fichier Runnable sur un gestionnaire Gestionnaire gestionnaire = new Handler (); handler.post (new Runnable () @Override public void run () // tâche va ici);
Il est également possible d’utiliser le gestionnaire d’interface utilisateur par défaut pour poster un message. Runnable
appel Activity.runOnUiThread ()
.
// publication de Runnable à l'aide de l'activité de gestionnaire d'interface utilisateur.runOnUiThread (new Runnable () @Override public void run () // tâche à effectuer);
Il est important de garder à l’esprit certaines choses à propos de Runnable
s. Contrairement à un Message
, une Runnable
ne peut pas être recyclé - une fois que son travail est terminé, il est mort. Comme il fait partie d’un package Java standard, un Runnable
ne dépend pas de Gestionnaire
et peut être appelé sur une norme Fil
en utilisant le Runnable.run ()
méthode. Cependant, cette approche n'a rien à voir avec le framework HaMeR et ne partage aucun de ses avantages..
le Message
objet définit un message contenant une description et des données arbitraires pouvant être envoyées et traitées via Gestionnaire
. le Message
est identifié avec un int
défini sur Message.what ()
. le Message
peut contenir deux autres int
arguments et un Objet
pour stocker différents types de données.
Message.quel
: int
identifier le Message
Message.arg1
: int
argument arbitraireMessage.arg2
: int
argument arbitraireMessage.obj
: Objet
pour stocker différents types de données Lorsque vous devez envoyer un message, au lieu de créer un message à partir de rien, il est recommandé de récupérer un message recyclé directement dans le pool global avec le message suivant: Message.obtain ()
ou Handler.obtainMessage ()
commandes. Il existe différentes versions de ces méthodes qui vous permettent d’obtenir une Message
selon vos besoins.
Un usage commun de Handler.obtainMessage ()
est le moment où vous devez envoyer un message à un fil d’arrière-plan. Vous utiliserez le Gestionnaire
associé à ce fil Looper
obtenir un Message
et l'envoyer au fil de fond, comme dans l'exemple ci-dessous.
int quoi = 0; String hello = "Bonjour!"; // Obtention du message associé au message de discussion en arrière-plan msg = handlerBGThread.obtainMessage (what, hello); // Envoi du message au thread d'arrière-plan handlerBGThread.sendMessage (msg);
Il y a beaucoup de méthodes sympas sur le Message
classe, et je vous conseille de regarder de plus près la documentation.
envoyer le message()
Les optionsDe la même manière que nous pouvons poster Runnable
s, il y a plusieurs options à envoyer Message
s:
Handler.sendMessage (Message msg)
: ajouter un Message
au MessageQueue
.Handler.sendMessageAtFrontOfQueue (Message msg)
: ajouter un Message
à l'avant de la MessageQueue
.Handler.sendMessageAtTime (Message msg, long timeInMillis)
: ajouter un Message
à la file d'attente à un moment précis.Handler.sendMessageDelayed (Message msg, long timeInMillis)
: ajouter un Message
à la file d'attente après un laps de temps spécifique.le Message
objets expédiés par Looper
sont traités par le gestionnaire avec la méthode Handler.handleMessage
. Tout ce que vous avez à faire est d’étendre la Gestionnaire
classe et substitue cette méthode pour traiter les messages.
classe publique MessageHandler extend Handler @Override public void handleMessage (Message msg) switch (msg.what) // handle 'Hello' msg case 0: String hello = (String) msg.obj; System.out.println (bonjour); Pause;
Le framework HaMeR peut aider à améliorer le code simultané de votre application Android. Cela peut sembler déroutant au premier abord par rapport à la simplicité d’un AsyncTask
, mais l'ouverture de HaMeR peut être un avantage, si elle est utilisée correctement.
Rappelles toi:
Handler.post ()
les méthodes sont utilisées lorsque les expéditeurs savent quelles opérations effectuer.Gestionnaire.sendMessage()
les méthodes sont utilisées lorsque le récepteur sait quelle opération effectuer.Pour en savoir plus sur le threading dans Android, le livre Efficient Android Threading: Techniques de traitement asynchrone pour les applications Android de Anders Goransson.
Dans le prochain tutoriel, nous allons continuer à explorer le framework HaMeR avec une approche pratique en construisant une application qui illustre différentes manières d'utiliser ce framework de concurrence Android. Nous allons créer cette application à partir de la base, en essayant différentes possibilités comme la communication entre Les fils
, parler avec le fil de l'interface utilisateur, envoyer des messages et poster Runnable
s avec des retards.
À bientôt!