Lorsqu'un composant d'application démarre et que l'application ne comporte aucun autre composant le système Android lance un nouveau processus Linux pour l'application avec un seul thread de l'exécution. Par défaut, tous les composants de la même application s’exécutent dans le même processus et thread, appelé thread main.
Si un composant d'application démarre et qu'un processus pour cette application, étant donné qu'un autre composant de l'application a déjà démarré, le composant démarre dans ce processus et utilise le même thread d'exécution. Cependant, vous pouvez faire en sorte composants de votre application pour qu'ils s'exécutent dans des processus distincts, et vous pouvez créer des les threads de tout processus.
Ce document explique le fonctionnement des processus et des threads dans une application Android.
Processus
Par défaut, tous les composants d'une application s'exécutent dans le même processus, et la plupart des applications ne le changez pas. Toutefois, si vous constatez que vous devez contrôler le processus vous pouvez le faire dans le fichier manifeste.
L'entrée du fichier manifeste pour chaque type d'élément de composant (<activity>
, <service>
, <receiver>
et <provider>
) accepte un attribut android:process
qui peut spécifier un
dans lequel le composant s'exécute. Vous pouvez définir cet attribut pour que chaque composant s'exécute
dans son propre processus ou de sorte que certains composants
partagent un processus tandis que d'autres ne le font pas.
Vous pouvez également définir
android:process
afin que les composants de différentes applications s'exécutent dans le même
, à condition que les applications partagent le même ID utilisateur Linux et soient signées avec le
les mêmes certificats.
<application>
accepte également un attribut android:process
, que vous pouvez utiliser pour définir
valeur par défaut qui s'applique
à tous les composants.
Android peut décider d'arrêter un processus à un moment donné, lorsque les ressources sont requises par d'autres processus qui servent plus immédiatement l'utilisateur. Application composants en cours d'exécution dans le processus qui est arrêté sont par conséquent détruits. Un processus est lancé à nouveau pour ces composants quand il y a du travail à faire.
Lorsqu'il décide des processus à arrêter, le système Android évalue leur importance relative l'utilisateur. Par exemple, il met plus facilement fin à un processus hébergeant des activités qui ne sont plus visibles à l'écran, par rapport à un processus hébergeant des activités visibles. La décision de décider s’il faut mettre fin à un processus, dépend donc de l'état des composants exécutés dans ce processus.
Les détails du cycle de vie du processus et de sa relation avec les états d’application sont abordés dans Processus et cycle de vie de l'application.
Threads
Lorsqu'une application est lancée, le système crée un thread d'exécution pour celle-ci,
appelé thread principal. Ce thread est très important, car il est
chargé d'envoyer des événements à
les widgets d'interface utilisateur appropriés, y compris les événements de dessin. Il est également
presque toujours le thread dans lequel votre application interagit avec les composants
à partir du android.widget
du kit UI Android et
android.view
packages.
Pour cette raison, le thread principal est parfois
appelé thread UI. Toutefois, dans certains cas particuliers,
n'est peut-être pas son thread UI. Pour en savoir plus, consultez la section Thread
des annotations.
Le système ne crée pas un thread distinct pour chaque instance d'un composant. Tout
les composants qui s'exécutent dans le même processus sont instanciés dans le thread UI, et les appels système à
sont distribués à partir de ce thread. Par conséquent, les méthodes qui répondent aux
des rappels, tels que onKeyDown()
pour signaler les actions des utilisateurs ou une méthode de rappel de cycle de vie, exécutez toujours le thread UI du processus.
Par exemple, lorsque l'utilisateur appuie sur un bouton à l'écran, le thread UI de votre application envoie le l'événement tactile au widget, qui à son tour définit son état d'appui et envoie une requête d'invalidation à dans la file d'attente des événements. Le thread UI retire la requête de la file d'attente et avertit le widget de redessiner. lui-même.
À moins d'implémenter correctement votre application, ce modèle monothread peut nuire aux performances lorsque votre application effectue un travail intensif en réponse à une interaction de l'utilisateur. Exécuter de longues opérations dans le thread UI, comme l'accès au réseau ou les requêtes de base de données, bloque l'ensemble de l'interface utilisateur. Lorsque le thread est bloqué, aucun événement ne peut être envoyé. y compris les événements de dessin.
Du point de vue de l'utilisateur, l'application semble se bloquer. Pire encore, si le thread UI est bloqué pendant plus de quelques secondes, l'utilisateur voit s'afficher le message "L'application ne répondant" (ANR). L'utilisateur peut alors décider de quitter l'application ou même de la désinstaller
N'oubliez pas que le kit d'UI Android n'est pas thread-safe. Alors, ne manipulez pas depuis un thread de nœud de calcul. Effectuer toute manipulation de votre interface utilisateur à partir de celle-ci thread. Il existe deux règles pour le modèle à thread unique d'Android:
- Ne bloquez pas le thread UI.
- N'accédez pas au kit UI Android en dehors du thread UI.
Threads de calcul
Grâce à ce modèle monothread, la réactivité de votre de l'application que vous ne bloquez pas le thread UI. Si vous avez des opérations à effectuer qui ne sont pas instantanées, assurez-vous de le faire en arrière-plan distinct ou threads de nœud de calcul. N'oubliez pas que vous ne pouvez pas mettre à jour l'UI à partir d'un thread autre que le thread UI, ou thread principal.
Pour vous aider à respecter ces règles, Android propose plusieurs façons d'accéder au thread UI à partir d'autres les threads. Voici une liste de méthodes qui peuvent vous aider:
L'exemple suivant utilise View.post(Runnable)
:
Kotlin
fun onClick(v: View) { Thread(Runnable { // A potentially time consuming task. val bitmap = processBitMap("image.png") imageView.post { imageView.setImageBitmap(bitmap) } }).start() }
Java
public void onClick(View v) { new Thread(new Runnable() { public void run() { // A potentially time consuming task. final Bitmap bitmap = processBitMap("image.png"); imageView.post(new Runnable() { public void run() { imageView.setImageBitmap(bitmap); } }); } }).start(); }
Cette implémentation est thread-safe, car l'opération en arrière-plan est effectuée à partir d'un thread distinct.
tandis que ImageView
est toujours manipulé à partir du thread UI.
Cependant, plus l'opération est complexe, plus ce type de code peut devenir compliqué
difficiles à gérer. Pour gérer des interactions plus complexes avec un thread de nœud de calcul, vous pouvez envisager
à l'aide d'un Handler
dans votre thread de travail ;
pour traiter les messages envoyés à partir du thread UI. Pour découvrir en détail comment
planifier le travail sur les threads en arrière-plan et communiquer avec le thread UI, voir
Présentation des tâches en arrière-plan
Méthodes compatibles avec les threads
Dans certains cas, les méthodes que vous implémentez sont appelées à partir de plusieurs threads, et doit donc être écrit pour être thread-safe.
Cela s'applique principalement aux méthodes pouvant être appelées à distance, telles que les méthodes dans un service lié. Lorsqu'un appel sur un
implémentée dans un IBinder
provient du même processus que celui
IBinder
est en cours d'exécution, la méthode est exécutée dans le thread de l'appelant.
Toutefois, lorsque l'appel provient d'un autre processus, la méthode s'exécute dans un thread choisi parmi
un pool de threads que le système gère dans le même processus que IBinder
.
Il n'est pas exécuté dans le thread UI du processus.
Par exemple, alors qu'un service
La méthode onBind()
est appelée à partir du thread UI de
processus du service, les méthodes implémentées dans l'objet renvoyé par onBind()
, telles que
qui implémente les méthodes d'appel de procédure à distance (RPC), sont appelées à partir de threads
dans la piscine. Étant donné qu'un service peut avoir plusieurs clients, plusieurs threads de pool peuvent s'engager
la même méthode IBinder
en même temps. Les méthodes IBinder
doivent donc être
implémenté pour être thread-safe.
De même, un fournisseur de contenu peut recevoir des demandes de données provenant d'autres processus.
ContentResolver
et ContentProvider
masquent les détails de la gestion de la communication inter-processus (IPC),
mais les méthodes ContentProvider
qui y répondent,
query()
,
insert()
,
delete()
,
update()
,
et getType()
:
appelé à partir d'un pool de threads dans le processus du fournisseur de contenu, et non de l'UI
pour le processus. Comme ces méthodes peuvent être appelées à partir de n'importe quel nombre de threads au niveau
dans le même temps, elles doivent aussi être
implémentées pour être thread-safe.
Communication inter-processus
Android propose un mécanisme d'IPC utilisant des RPC, dans lequel une méthode est appelée par une activité ou une autre application. , mais exécuté à distance dans un autre processus. Tous les résultats sont renvoyés au appelant. Cela implique de décomposer un appel de méthode et ses données à un niveau que le système d'exploitation peut comprendre, en les transmettant du processus et de l’espace d’adressage locaux vers le processus distant et l'espace d'adressage, puis y reconstituer l'appel.
Les valeurs renvoyées sont alors transmis dans la direction opposée. Android fournit tout le code nécessaire pour effectuer ces IPC transactions, ce qui vous permet de vous concentrer sur la définition et l'implémentation de l'interface de programmation RPC.
Pour effectuer l'IPC, votre application doit s'associer à un service à l'aide de bindService()
. Pour en savoir plus, consultez la page Présentation des services.