Présentation des processus et des threads

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:

  1. Ne bloquez pas le thread UI.
  2. 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.