*Tutoriel et exemples sur le Threading d'Android

Ceci est notre tutoriel sur le threading sous Android. Nous explorons ce qu'est un thread et fournissons plusieurs abstractions pour la classe Thread.

Qu'est-ce qu'un Thread ?

Un thread est un chemin d'exécution qui existe au sein d'un processus.

Un processus peut avoir un ou plusieurs threads.

Un processus Single-threaded a un thread tandis qu'un processus multi-threaded a plus d'un thread.

Dans le processus single-threaded, nous n'avons qu'un seul flux d'exécution des instructions alors que dans le processus multi-threaded, nous avons plusieurs jeux d'instructions exécutés simultanément.

Un processus multi-threaded a des parties qui s'exécutent simultanément et chaque partie peut effectuer une tâche donnée indépendamment.

Le multi-threading est donc un mécanisme qui nous permet d'écrire des programmes d'une manière telle que plusieurs activités peuvent se dérouler simultanément dans le même programme.

Et surtout dans l'environnement actuel des appareils multicœurs, les développeurs devraient être capables de créer des lignes d'exécution concurrentes qui combinent et agrègent des données provenant de plusieurs ressources.

Mais il est également important de noter qu'en réalité, un système qui ne possède qu'un seul cœur d'exécution peut créer l'illusion d'une exécution simultanée. Pour ce faire, il exécute les différents threads de manière entrelacée.
Mais il le fait rapidement de telle sorte que nous pensons qu'il effectue réellement les tâches de manière concurrente.

Le Thread principal

Normalement, lorsque vous lancez votre projet, votre processus application démarre. D'abord, il y aura des threads pour le Runtime Android ou la machine virtuelle Dalvik.

A part cela, le système Android va créer un thread d'exécution appelé main. Ce sera le thread principal de votre application.

Ce thread est aussi parfois appelé le thread de l'interface utilisateur.

Votre application peut avoir beaucoup d'autres threads, normalement appelés threads d'arrière-plan. Cependant, le thread principal est le plus important. C'est ce thread qui est responsable de l'interaction avec les composants et les vues Android. Il les rend et met également à jour leurs états.

Ce thread est très important, d'autant plus que, comme nous l'avons dit, c'est là que tous les composants Android (Activity, Services, BroadcastReceiver ) sont exécutés par défaut.

Ce thread est le responsable de la gestion et de l'écoute des événements de saisie de l'utilisateur. En raison de son importance, il est toujours conseillé de le garder réactif en.. :

  1. N'effectuant aucune tâche susceptible de prendre du temps comme les entrées/sorties (I/O) dans ce thread. Ces tâches peuvent bloquer le thread principal pendant un temps indéfini et doivent donc être transférées à un thread d'arrière-plan.
  2. Ne pas faire de tâches gourmandes en ressources CPU dans ce thread. Si vous avez des calculs ou des tâches coûteuses comme l'encodage vidéo, vous devez les décharger également sur un thread d'arrière-plan.

Ce thread a normalement un dispositif attaché à lui appelé Looper. Le Looper contient une MessageQueue. Une MessageQueue est juste une file d'attente de messages avec une certaine unité de travail qui doivent être exécutés séquentiellement.

Ainsi, lorsqu'un message est prêt à être traité dans la file, le Looper Thread va extraire ce message de la file. Ce message sera transmis de manière synchrone (séquentielle) au gestionnaire cible. Ce gestionnaire est déjà spécifié dans le message.

Ensuite, le Handler va commencer son travail et le faire. Lorsqu'il a terminé son travail, le Looper thread commence à traiter le prochain message disponible dans la file d'attente et le transmet pour qu'il soit également exécuté.

Vous pouvez voir que ce processus est séquentiel. Donc, si notre Handler ne termine pas son travail rapidement, le Looper restera là à attendre le traitement d'autres messages en attente dans la file d'attente.

Dans ce cas, le système affichera la boîte de dialogue Application Not Responding(ANR). Vous avez peut-être déjà vu cela dans certaines applications. Cela signifie que l'application ne répond pas aux entrées de l'utilisateur. Pourtant, elle est occupée à travailler.

La boîte de dialogue ANR sera affichée aux utilisateurs si une application ne répond pas aux entrées de l'utilisateur dans les cinq secondes. Le système offrira alors aux utilisateurs la possibilité de quitter l'application.

Vous rencontrerez ce type de scénario lorsque vous tenterez d'effectuer des tâches intensives dans votre thread principal. C'est-à-dire, par exemple, lorsque vous essayez de faire ce qui suit dans votre thread principal :

  1. Accéder au Réseau/Services Web/Internet
  2. Accéder aux ressources du système de fichiers.
  3. Essayer de traiter de grandes quantités de données ou de faire des calculs mathématiques complexes, etc.

La plupart du code que vous écrivez comme dans vos activités, fragments, services s'exécutent normalement dans le thread principal par défaut, à moins que vous ne créiez explicitement un thread d'arrière-plan.

Le SDK Android est basé sur un sous-ensemble du SDK Java. Le SDK Java est dérivé du projet Apache Harmony et permet d'accéder à des constructions de concurrence de bas niveau telles que :

  1. java.lang.Thread.
  2. java.lang.Runnable.
  3. Mots clés synchronized et volatile.

La classe Thread.

La classe java.lang.Thread est la construction la plus basique utilisée pour créer des threads.

C'est aussi la plus utilisée. Cette classe nous crée une nouvelle ligne d'exécution indépendante dans un programme Java.

Une façon de créer un nouveau thread est simplement en sous-classant ou en étendant la classe java.lang.Thread.

public class MyThread extends Thread {
    public void run() {
        Log.d("Generic", "Our thread is running ...");
    }
}

Nous pouvons alors effectuer notre tâche de fond à l'intérieur de la méthode run().

Cependant ce thread n'est pas encore démarré. Pour cela, nous devons instancier cette classe et démarrer explicitement notre thread :

    MyThread myThread = new MyThread();
    myTread.start();

La méthode start() réside dans la classe Thread. L'invoquer demande au système de créer un thread à l'intérieur du processus et exécute la méthode
méthode run(). La méthode run() sera exécutée automatiquement si nous invoquons la méthode start().

Méthodes communes de Threading.

**(a). Thread.currentThread()`

Cette méthode retourne le Thread de l'appelant, c'est-à-dire le Thread courant.

**(b). Thread.sleep(time)`

Cette méthode fera dormir le thread qui a envoyé ce message pendant l'intervalle de temps donné (donné en millisecondes et nanosecondes). La précision n'est pas garantie - le Thread peut dormir plus ou moins longtemps que demandé.

Fondamentalement, il met en pause l'exécution du thread actuel pour la
période de temps donnée.

(c). getContextClassLoader()

Cette méthode retourne le ClassLoader du contexte pour ce Thread.

(d). start()

Cette méthode démarrera le nouveau Thread d'exécution. La méthode run() du récepteur sera appelée par le Thread récepteur lui-même (et non par le Thread qui appelle start()).

(e). Thread.getName() et Thread.getId().

Ils obtiendront respectivement le name et le TID. Elles sont principalement utilisées à des fins de débogage.

(f) Thread.isAlive()

isAlive() vérifiera si le thread est en cours d'exécution ou s'il a déjà terminé son travail.
a déjà terminé son travail.

(g) Thread.join()

join() bloquera le thread actuel et attendra que le thread auquel on a accédé
le thread auquel on accède termine son exécution ou meurt.

Comment maintenir la réactivité de l'application

La meilleure façon de maintenir la réactivité d'une application n'est pas d'éviter les opérations longues. Il s'agit plutôt de les décharger du thread principal afin qu'elles soient
principal afin qu'elles puissent être traitées en arrière-plan par un autre thread.

Le thread principal peut alors continuer à traiter les mises à jour de l'interface utilisateur en douceur et répondre en temps voulu aux interactions des utilisateurs.

Normalement, il y a un ensemble d'opérations typiques qui sont communes dans de nombreuses applications et qui consomment non seulement beaucoup de temps mais aussi des ressources du dispositif.

Ces opérations comprennent :

  • L'accès et la communication via le réseau, en particulier Internet.
  • Les opérations d'entrée et de sortie de fichiers. Elles se produisent sur le système de fichiers local.
  • Traitement d'images et de vidéos.
  • Calculs mathématiques complexes.
  • Traitement de texte - Essayer de traiter ou d'analyser une grande masse de texte.
  • Encodage et décodage de données.

Exemples rapides de Threading.

1. Créer un simple Timer avec la classe Thread.

C'est une classe pour montrer comment implémenter un simple timer. Il n'imprime pas notre quoi que ce soit et est juste une classe montrant comment mettre en œuvre une telle idée.

import java.lang.Thread;

public class TimerClass extends Thread{

    boolean timeExpired;
    double mTime;
    /** Creates a new instance of TimerClass */
    public TimerClass(double time){
        mTime = time;
    }

    public void run(){

        timeExpired = true;
        mTime = mTime * 1000;
        double startTime = System.currentTimeMillis();
        double stopTime = startTime + mTime;
        while(System.currentTimeMillis() < stopTime && timeExpired == false){
              try {
                Thread.sleep(10);
            } catch (InterruptedException e){ }
        }

        timeExpired = true;

    }

    public boolean getTimeExpired(){
        return true;
    }

    public void cancel(){
        timeExpired = true;
    }

}

2. Classe utilitaire Thread complète et réutilisable.

import android.os.Looper;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Threading tools
 * </p>
 */
public class ThreadUtils {

    private final static ExecutorService sThreadPool = Executors.newCachedThreadPool();

    /**
     * Current thread
     */
    public static Thread currentThread() {
        return Thread.currentThread();
    }

    /**
     * Current process ID
     */
    public static long currentThreadId() {
        return Thread.currentThread().getId();
    }

    /**
     * Current process name
     */
    public static String currentThreadName() {
        return Thread.currentThread().getName();
    }

    /**
     * Determine if it is a UI thread
     */
    public static boolean isUiThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    /**
     * Runs on the UI thread
     */
    public static void runOnUiThread(Runnable action) {
        if (action == null) {
            return;
        }
        if (Looper.myLooper() == Looper.getMainLooper()) {
            action.run();
        } else {
            HandlerUtils.uiPost(action);
        }
    }

    /**
     * Runs in the background thread
     */
    public static void runOnBackgroundThread(Runnable action) {
        if(action==null){
            return;
        }
        if (Looper.myLooper() != Looper.getMainLooper()) {
            action.run();
        }else{
            sThreadPool.submit(action);
        }
    }

    /**
     * Run on asynchronous thread
     */
    public static void runOnAsyncThread(Runnable action) {
        if (action == null) {
            return;
        }
        sThreadPool.submit(action);
    }

    /**
     * Runs on the current thread
     */
    public static void runOnPostThread(Runnable action) {
        if(action==null){
            return;
        }
        action.run();
    }

    public static void backgroundToUi ( final Runnable background , final Runnable ui ) {
        runOnBackgroundThread(new Runnable() {
            @Override
            public void run() {
                background.run();
                runOnUiThread ( ui );
            }
        });
    }
}

Catégorisé: