Dans ce tutoriel, nous expliquerons les comment Android agit lors de l'exécution d'un service, nous décrirons en quoi consistent les threads d'exécution et en quoi consistent les processus. Cela nous permettra de comprendre la façon dont nos applications sont exécutées, nous donnant un meilleur contrôle et une plus grande stabilité sur les appareils mobiles sur lesquels elles seront installées.
Fil
Lorsque l'utilisateur exécute une application, Android crée un fil appelé main (main). Ce fil est très important car il est en charge de gérer les événements que l'utilisateur déclenche sur les composants appropriés et comprend également les événements qui dessinent l'écran. Un fil d'exécution, la plus petite partie pouvant être traitée par un ordonnanceur dans un système d'exploitation, en l'occurrence Android (avec noyau Linux).
La mise en place de plusieurs threads qui sont traités en même temps dans la même application, (appelons-le concomitance, qui fait référence à la simultanéité d'exécution), c'est ce qu'on appelle le multithreading. Le multithreading est appliqué pour que ces threads partagent des ressources Et c'est ce que comprend un processus, rappelez-vous que cela peut être appliqué par programmation au sein du code d'une même application, la mise en œuvre du multithreading au niveau du système d'exploitation ne dépend pas de nous.
Le début du cycle de vie d'une application comprend la génération d'un nouveau processus Linux auquel est affecté un fil principal ou fil UI (le fil qui est responsable du traitement graphique de l'application, fil d'interface utilisateur en anglais).
NoterLe cycle de vie comprend l'exécution des méthodes : onCreate (), onStart () et onResume (); à son début et à sa fin : onPause (), onStop () et onDestroy ().
Un processus peut être forcé de se fermer par Android par manque de mémoire, ce type de cas est rare en raison des avancées technologiques mais cela arrive quand même.
La question est: Quels processus Android décide de fermer ?
Ceux-ci sont clôturés en comparant leur niveau d'importance, il se résume comme suit :
Le plus important : les processus de premier planL'utilisateur interagit avec ledit processus (la méthode onResume() dudit processus est en cours d'exécution). Il existe un service qui exécute ses méthodes de cycle de vie. Ou y a-t-il un DiffusionRécepteur courir son onReceive () méthode.
Le deuxième plus important : les processus visiblesActivité avec appel à méthode onPause(). Service lié à une activité visible (service lié).
Le troisième plus important : Traiter avec un serviceL'utilisateur n'interagit pas directement avec le processus. Le processus a un service exécuté en arrière-plan.
Le deuxième moins important : le processus d'arrière-planIl n'y a aucun type d'interaction avec l'utilisateur. Le processus le plus récemment consulté par l'utilisateur sera le dernier à être détruit.
Le moins important : Processus videIl n'a pas de composants actifs. Le processus est toujours actif à des fins de mise en cache, empêchant l'utilisateur de revenir à l'utilisation de ce processus.
Ce dernier, le processus vide, est le premier à se terminer en cas de manque de mémoire. Ainsi, une application qui implémente un service où un fil est créé pour télécharger du contenu depuis Internet, sera plus importante qu'une application qui crée le fil sans implémenter un service, de sorte qu'il est plus susceptible d'être terminé avant de terminer le téléchargement. , car ce sont des processus de longue durée.
Pour comprendre le multhreading voyons comment Android gère son thread principal.
PROCESS A a une interface utilisateur ou fil PRINCIPAL, ce fil gère un file d'attente de messages ou la file d'attente de messages, qui s'exécute lorsque le thread devient inactif, qui gère cela ? Le Boucleur.
Looper est une classe d'interface utilisateur de Android Java qui, avec le Classe de gestionnaire, traite les événements de l'interface utilisateur tels que les pressions sur les boutons, les écrans redessinés et les commutateurs d'orientation. Les événements peuvent également être utilisés pour charger du contenu dans un service HTTP, redimensionner des images et exécuter des requêtes à distance. La principale caractéristique de ces classes est qu'elles sont capables d'implémenter un modèle de concurrence.
La Classe de boucleur Android contient un File d'attente de messages (file d'attente de messages) et n'est associé qu'au sujet à partir duquel il a été créé. Veuillez noter que cette connexion ne peut pas être interrompue et que le lLooper il ne peut être attaché à aucun autre fil. De plus, le Looper est sur le stockage local et ne peut être appelé qu'à partir d'une méthode statique. Une méthode de staging vérifie si un Looper est déjà associé à un thread, puis la méthode statique crée le Looper. Ensuite, une boucle peut être utilisée pour vérifier les messages dans la file d'attente.
Jusqu'à présent, nous comprenons plusieurs concepts : processus, thread, thread d'interface utilisateur, boucleur, mais nous ne savons toujours pas pourquoi le multithreading.
Opérations à long terme
Elle est considérée comme longue durée pour toute méthode dont l'exécution dépasse 5 secondes, ce qui déclenche le message type « l'application ne répond pas. Voulez-vous le fermer ?
Quelles peuvent être ces opérations ? : Accès Internet, Requêtes SQL, analyse XML / HTML / JSON, traitement graphique complexe. N'importe laquelle de ces opérations exécutées dans le thread principal le bloquera, et puisque c'est celle qui gère l'interface utilisateur graphique, elle est interprétée comme un gel, qu'android décide de fermer.
Imaginons simplement que l'une de ces opérations dure 7 secondes et que l'utilisateur décide d'écrire quelque chose dans une entrée de texte. Ainsi, bien que ces 7 secondes ne se soient pas écoulées, le thread de l'interface utilisateur ne peut pas mettre à jour la vue afin que l'utilisateur apprécie qu'il écrit, et il génère donc un gel, le message "pas de réponse" est déclenché avec lequel vous avez deux options, attendre ou détruire, bien que vous ne puissiez jamais savoir combien de temps attendre, cela peut prendre quelques secondes voire quelques minutes selon la file d'attente des messages qui ont le fil principal.
Comment éviter le gel ?
A l'aide de threads ou de services, selon que la tâche nécessite ou non de modifier la vue, dans ce cas un service est implémenté car la vue d'une application ne peut pas être modifiée en dehors du thread UI. Le meilleur moyen d'éviter le gel est d'utiliser des tâches asynchrones avec la classe AsyncTask, dans ce tutoriel, nous allons implémenter plusieurs threads pour comprendre le comportement de l'architecture Android.
Code et développement
Le projet que nous allons créer ensuite sera basé sur un téléchargement d'image avec lequel nous devons créer un fil qui nous permet de gérer l'accès et le téléchargement sur Internet car le PRINCIPALE ou alors Fil d'interface utilisateur ne permet pas cette action.
Nous allons commencer par créer un nouveau projet avec une activité vide, nous avons intitulé ce projet "Exemple multithread", avec une seule activité simple nous allons créer la structure du fichier XML qui appartient à cette activité.
Nous avons un champ de texte, un bouton, une disposition linéaire qui correspond à une barre de chargement indéterminée que nous utiliserons plus tard, et une vue liste qui contient un tableau d'URL d'images hébergées sur internet. Dans le fichier qui contient la classe Java pour notre activité (unique), elle est écrite avec le code suivant :
package com.omglabs.multithreaexample; importer android.support.v7.app.AppCompatActivity ; importer android.os.Bundle ; importer android.view.View ; importer android.widget.AdapterView; importer android.widget.EditText; importer android.widget.LinearLayout ; importer android.widget.ListView ; importer android.widget.ProgressBar ; la classe publique MainActivity étend AppCompatActivity implémente AdapterView.OnItemClickListener {private EditText editText; privé ListView listView; URL de chaîne privée []; barre de progression privée progressBar; private LinearLayout progressLayout; @Override protected void onCreate (Bundle protectedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); editText = (EditText) findViewById (R.id.downloadURL); listView = (ListView) findViewById (R.id.listurls); listView.setOnItemClickListener (ceci); urls = getResources().getStringArray (R.array.URLs); progressBar = (ProgressBar) findViewById (R.id.progressbar); progressLayout = (LinearLayout) findViewById (R.id.progresslayout); } public void download (View view) {} @Override public void onItemClick (AdapterView adapterView, View view, int i, long l) {editText.setText (urls [i]); }}Jusqu'à présent l'application peut être compilée sans problème, dans cette classe, on déclare les variables :
- éditer le texte
- listeView
- URL
- barre de progression
- progressionMise en page
Un champ de texte, une liste, un arrangement de chaînes, une barre de progression et une disposition linéaire.
Dans le méthode onCreate Nous leur attribuons la vue respective qui leur appartient et qui ont été créées dans le fichier XML de l'activité, à l'exception des urls qui attribuent ses valeurs à partir du dossier des valeurs dans le fichier de chaîne et dont l'arrangement est déclaré comme suit:
http://www.fmdos.cl/wp-content/uploads/2016/03/1.jpg.webp http://vignette3.wikia.nocookie.net/teenwolf/images/9/90/Crystal_Reed_003.jpeg.webp https : // pbs.twimg.com/profile_images/699667844129107968/EvhTFBHN.jpg.webp http://vignette1.wikia.nocookie.net/teen-wolf-pack/images/0/0b/Holland-holland-roden-31699868-500-600.png.webpLa méthode de téléchargement vide (View view) sera renseignée avec le code qui fera le téléchargement et qui est lié au Bouton de téléchargement Bot via l'attribut onclick. Finalement, le méthode onitemclick qui appartient à liste, il remplit le champ de texte lorsque vous cliquez sur l'une des URL contenues dans la liste. Une fois compilé, ce code ressemblera à ceci :
Dans l'étape suivante, nous allons créer les méthodes qui procéderont au téléchargement, en suivant ces étapes :
- Créez un objet de la classe URL (java.net) qui représentera l'url à télécharger.
- Ouvrez la connexion à l'aide de cet objet.
- Lisez les données (via le Web) à l'aide de la classe de flux d'entrée dans un tableau d'octets.
- Ouvrez / créez un fichier de flux de sortie où les données URL seront enregistrées sur la carte SD.
- Écrivez les données dans ce fichier.
- Et enfin fermer la connexion.
Pour l'instant ça ressemblera à ça :
téléchargement booléen public usingThreads (lien chaîne) {confirmation booléenne = false; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; essayez {downloadLink = nouvelle URL (lien); connection = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); } catch (MalformedURLException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } enfin {if (connex! = null) {connex.disconnect (); } if (inputStream! = null) {essayez {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }}} retour de confirmation; }Cette méthode que nous avons construite n'aura besoin que d'un Chaîne de caractères qui sera l'URL à télécharger, est booléen Pour confirmer le téléchargement, downloadLink est l'objet URL, connection est la connexion qui sera établie pour accéder à l'objet et inputStream est celui qui procédera à la lecture des données, si nous essayons d'utiliser cette méthode sur le bouton téléchargerBot l'application s'arrêterait en raison de l'impossibilité de s'exécuter sur le fil principal.
Ici, nous allons avec l'utilisation de threads, il y a deux façons de le faire avec une classe et c'est en étendant cette classe à Thread ou en implémentant la classe Runnable, cette classe n'est pas un thread elle vous permet simplement de créer une méthode que vous peut s'exécuter à un moment précis et si vous créez un thread séparé, exécutez-le dedans.
À l'intérieur du bouton de téléchargement, nous écrirons ce code, et il ressemblera à ceci :
public void download (View view) {Thread mThread = new Thread (new mRunn ()); mThread.start (); }Ici, nous créons un nouveau thread qui a besoin d'un objet Runnable que nous créons dans une classe privée comme celle-ci :
la classe privée mRunn implémente Runnable {@Override public void run () {télécharger usingThreads (urls [0]); }}Créer un cours privé
NoterN'oubliez pas que tout cela est dans la classe Java de notre seule activité.
Avec la ligne :
télécharger en utilisantThreads (urls [0]);Nous appelons la fonction que nous avons créée à l'endroit où nous avons ouvert la connexion, un élément du tableau d'URL lui est transmis afin qu'il puisse lire les données de cette adresse. Plus tard, il sera modifié.
Si nous essayions d'exécuter cette application en appuyant sur le bouton, l'application s'arrêterait, car nous avons besoin d'une autorisation spéciale pour accéder à Internet, qui est demandée via le manifeste de notre application. Ajout de la ligne, avant l'étiquette :
Maintenant, pour vérifier que l'application effectue réellement le téléchargement, nous allons ajouter quelques lignes de code au méthode de téléchargement utilisantThreads, Il ressemblera à ceci:
téléchargement booléen public usingThreads (lien chaîne) {confirmation booléenne = false; URL downloadLink = null; HttpURLConnection conne = null; InputStream inputStream = null; FileOutputStream archOutputStream = null; Fichier fichier = nul; essayez {downloadLink = nouvelle URL (lien); connection = (HttpURLConnection) downloadLink.openConnection (); inputStream = conne.getInputStream (); fichier = nouveau fichier (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (lien) .getLastPathSegment ()); archOutputStream = nouveau FileOutputStream (fichier); int Lecture = -1; octet [] buffer = nouvel octet [1024] ; while ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } confirmation = vrai; } catch (MalformedURLException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } enfin {if (connex! = null) {connex.disconnect (); } if (inputStream! = null) {essayez {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }} if (archOutputStream! = null) {essayez {archOutputStream.close (); } catch (IOException e) {e.printStackTrace (); }}} retour de confirmation ; } FileOutputStream archOutputStream = null; Fichier fichier = nul ;Les déclarations de ces objets représentent l'écriture du fichier en cours de lecture, et le fichier vide où la lecture sera enregistrée.
fichier = nouveau fichier (Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS) + "/" + Uri.parse (urls [0]). getLastPathSegment ()); archOutputStream = nouveau FileOutputStream (fichier); int Lecture = -1; octet [] buffer = nouvel octet [1024]; while ((Read = inputStream.read (buffer))! = -1) {archOutputStream.write (buffer, 0, Read); } confirmation = vrai;"Fichier" est l'objet Fichier vide dont l'adresse est construite en accédant à la carte SD "Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS)" et en ajoutant une barre oblique "/" et le dernier segment de l'URL qui représente généralement le nom du fichier à download , nous y parvenons avec la méthode getLastPathSegment ().
Avant de tester l'application, nous allons ajouter une dernière autorisation dans le manifeste :
Après avoir exécuté l'application sur l'émulateur ou l'appareil Android, en appuyant sur le bouton, nous verrons qu'apparemment rien ne se passe, mais si nous vérifions le dossier de téléchargement avec un explorateur de fichiers, nous nous rendrons compte que le premier élément de la liste a été téléchargé; une photo appelée 1.jpg.webp.
Pour le faire application dynamique et implémenter les URL de la listview, nous mettrons à jour le méthode de téléchargement (Afficher la vue) et nous ajouterons ceci, comme première ligne :
Lien chaîne = editText.getText().ToString();Et dans le Classe mRunn nous allons ajouter ceci, avant la méthode run() :
la classe privée mRunn implémente Runnable {lien de chaîne privé; public mRunn (lien chaîne) {this.link = lien; } @Override public void run () {télécharger usingThreads (lien); }}Et dans le Classe mRunn nous allons ajouter ceci, avant la méthode run() :
Nous pouvons donc passer la variable de lien du champ de texte à la méthode qui effectue le téléchargement. L'application à ce stade est entièrement fonctionnelle, même si elle manque un peu de convivialité, nous allons donc essayer de résoudre ce problème en utilisant la barre de progression que nous avons déclarée au début.
Dans la classe mRunn de la méthode run(), nous inclurons :
MainActivity.this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.VISIBLE);}});Avant l'appel au downloadusandoThreads. Cela fera apparaître la barre de chargement lorsque nous appuierons sur le bouton, dans la clause finally du méthode de téléchargement à l'aide de Threads.
Nous ajouterons :
this.runOnUiThread (new Runnable () {@Override public void run () {progressLayout.setVisibility (View.GONE);}});Ainsi, lorsque le téléchargement est terminé, la barre disparaît à nouveau. Cela se produira que le téléchargement soit réussi ou non.
Et cela a été tout, un brève implémentation de plusieurs threadsC'est un peu fastidieux et apporte quelques complications pour des applications plus complexes.Le moyen le plus efficace d'accomplir cette tâche, dans notre cas en téléchargeant des images, consiste à utiliser le Tâches asynchrones.