Android: quand dois-je utiliser un gestionnaire () et quand dois-je utiliser un thread?


129

Lorsque j'ai besoin de quelque chose à exécuter de manière asynchrone , comme une tâche de longue durée ou une logique qui utilise le réseau, ou pour une raison quelconque, démarrer un nouveau thread et l'exécuter fonctionne correctement. Créer un gestionnaire et l'exécuter fonctionne également. Quelle est la différence? Quand dois-je utiliser chacun d'eux? Quels sont les avantages / raisons d'utiliser a Handleret non a Thread?

PS. - Pour le bien de cette question, ignorons AsyncTask. - le Handler().postDelayedcas d'utilisation est clair pour moi, pour cette question, supposons que j'ai besoin que la tâche commence immédiatement.


Dans votre situation, allez tout droit et utilisez un nouveau Thread, ma prochaine suggestion serait AsyncTask mais ce n'est pas ce que vous voulez clairement. Les gestionnaires sont principalement utilisés si vous souhaitez ajouter un délai ou un autre type de personnalisation à un exécutable.
kabuto178

1
@ kabuto178 eh bien, il y a d'autres avantages des gestionnaires à mentionner que vous avez ignorés. Par exemple, être capable d'interagir avec le thread d'interface utilisateur à partir d'un thread séparé ..
tony9099

Réponses:


168

Si ce que vous faites est "lourd", vous devriez le faire dans un fil de discussion. Si vous ne le démarrez pas explicitement dans son propre thread, il s'exécutera sur le thread principal (UI) qui peut être perceptible comme une interface instable ou lente à répondre par vos utilisateurs.

Il est intéressant de noter que lorsque vous utilisez un thread, il est souvent utile d'utiliser également un Handler comme moyen de communication entre le thread de travail que vous démarrez et le thread principal.

Une interaction Thread / Handler typique peut ressembler à ceci:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

Cependant, en général, vous devez utiliser un thread à chaque fois que vous effectuez un travail qui pourrait être long ou très intensif (c'est-à-dire tout ce qui concerne le réseau, les E / S de fichiers, l'arithmatique lourde, etc.).


Merci pour la réponse rapide et le temps investi (et la rapidité de votre réponse !!)! Alors, laissez-moi voir si j'ai ceci: Le gestionnaire est conçu pour faciliter la communication non bloquante entre les threads de travail et le thread de l'interface utilisateur?
JRun

3
@JRun C'est l'une des utilisations oui. Consultez la description du gestionnaire dans la documentation java pour obtenir des informations intéressantes à ce sujet. Y compris une autre de ses utilisations (pour planifier les messages et les exécutables à exécuter à un moment donné dans le futur).
FoamyGuy

bien expliqué @FoamyGuy!
tony9099

Salut, est-il garanti que updateUI()cela fonctionnera après onCreateView(après le chargement de nouvelles vues)?
Zyoo

1
Pourquoi ça message.what()? Ne serait-ce pas juste if(msg == 0){? Merci beaucoup! :)
Ruchir Baronia

64

Handler et Thread sont vraiment deux choses différentes.

Un thread doit être créé pour exécuter des travaux de longue durée.

Un Handler est un objet très pratique pour communiquer entre 2 threads (par exemple: un thread d'arrière-plan doit mettre à jour l'interface utilisateur. Vous pouvez utiliser un gestionnaire pour publier un Runnable depuis votre thread d'arrière-plan vers le thread d'interface utilisateur).

Vous n'avez donc pas le choix entre Handler ou Thread. Utilisez un fil pour faire des travaux lourds! (vous pouvez utiliser un gestionnaire si votre thread d'arrière-plan déclenchera une tâche dans un autre thread - la plupart du temps, le thread d'interface utilisateur)


Merci pour la réponse rapide et le temps investi (et la rapidité de votre réponse !!)!
JRun

28

Handleret Threadsont deux choses différentes, mais elles ne se contredisent pas. Vous pouvez avoir un Handleret un Threaden même temps et chacun Handlerdoit en fait être exécuté dans un fichier Thread.

Pour plus de détails, vous pouvez consulter cet article .

entrez la description de l'image ici


19

A Handlers'exécute sur le même Thread, a Threads'exécute sur un fil différent.

Utilisez un gestionnaire si vous avez besoin d'exécuter quelque chose sur le même thread , généralement un élément d'interface graphique ou quelque chose comme ça.

Utilisez un thread si vous voulez que le thread principal reste libre de faire d'autres choses . Utilisez-le pour tout ce qui prend beaucoup de temps.


6
pourquoi devrais-je utiliser un gestionnaire si je veux exécuter quelque chose sur le même thread? quel est le but de la méthode mHandler.post (...)?
Elias

1
Elias, dans un tel cas, vous pouvez utiliser le gestionnaire si vous souhaitez qu'une certaine tâche s'exécute après un certain temps, ou répéter une tâche tous les X temps. Si vous ne voulez pas utiliser ces choses, vous avez raison. il est indigne d'utiliser un gestionnaire. vous pouvez simplement faire les choses GUI juste là et ensuite, bcoz vous êtes de toute façon dans le thread de l'interface utilisateur, car le gestionnaire s'exécute sur le thread dans lequel il a été créé.
tony9099

14

Les gestionnaires sont le meilleur moyen de communication entre l'arrière-plan et le thread d'interface utilisateur. Généralement, les gestionnaires sont associés à la file d'attente de messages d'un thread et ils sont utilisés pour envoyer des messages et peuvent être exécutés vers le message.

UTILISATION:

Thread: Pour effectuer des tâches dans le thread saperate (arrière-plan) que le thread UI (aide à débloquer le fil de l'interface utilisateur)

Handler Utilisé pour communiquer entre l'interface utilisateur et le thread d'arrière-plan.

Jetez un œil à cet article


4

Si vous devez mettre à jour l'interface utilisateur à partir d'un nouveau thread, vous devez vous synchroniser avec le thread de l'interface utilisateur.

Vous pouvez utiliser la classe android.os.Handler ou la classe AsyncTasks pour cela.

La classe Handler peut mettre à jour l'interface utilisateur. Un gestionnaire fournit des méthodes pour recevoir des instances de la classe Message ou Runnable.

Votre fil peut envoyer des messages via la méthode sendMessage (Message msg) ou via la méthode sendEmptyMessage ().

... plus d'informations ici sur les threads, etc. (comprend des turoriaux pour les différents mécanismes de thread et de synchronisation et quand utiliser quoi)


Merci d'avoir pris le temps de répondre à ma question. J'adore le blog de Lars Vogel, il est très perspicace et facile à suivre. Merci!
JRun

2

Quels sont les avantages / raisons d'utiliser un gestionnaire et non un thread?

Un gestionnaire vous permet d'envoyer et de traiter des messages et des Runnableobjets associés à un thread MessageQueue. Chaque Handlerinstance est associée à un seul thread et à la file d'attente de messages de ce thread.

Lorsque vous créez un nouveau Handler, il est lié au thread / file d'attente de messages du thread qui le crée - à partir de ce moment, il remettra les messages et les exécutables à cette file d'attente de messages et les exécutera lorsqu'ils sortent de la file d'attente de messages. .

Il existe deux utilisations principales pour un gestionnaire:

  1. Pour planifier les messages et les exécutables à exécuter à un moment donné dans le futur
  2. Pour mettre en file d' attente une action à effectuer sur un thread différent du vôtre.

Si vous utilisez des threads java, vous devez gérer vous-même quelque chose - la synchronisation avec le thread principal, l'annulation d'un thread, etc.

Ce thread unique ne crée pas de pool de threads sauf si vous utilisez ThreadPoolExecutorou ExecutorServiceAPI.

(Tiré de cette requête de vos commentaires sur la réponse Blackbelt)

Pourquoi ne pas utiliser un exécuteur? et même si je voulais utiliser un Handler pour faire ça, comment?

Référence: article Thread Performance

Il existe certains types de travail qui peuvent être réduits à des tâches hautement parallèles et distribuées. Avec le volume de paquets de travail que cela crée, AsyncTasket HandlerThreadne sont pas des classes appropriées. La nature AsyncTaskmonothread de transformerait tout le travail threadpool en un système linéaire. L'utilisation de la HandlerThreadclasse, en revanche, nécessiterait que le programmeur gère manuellement l'équilibrage de charge entre un groupe de threads.

ThreadPoolExecutor est une classe d'assistance pour faciliter ce processus. Cette classe gère la création d'un groupe de threads, définit leurs priorités et gère la répartition du travail entre ces threads. À mesure que la charge de travail augmente ou diminue, la classe tourne ou détruit davantage de threads pour s'adapter à la charge de travail.

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Vous pouvez consulter cet article du guide du développeur sur create-threadpool pour plus de détails.

Jetez un œil à cet article pour l'utilisation de Handlerpour exécuter plusieurs instances exécutables. Dans ce cas, toutes les Runnabletâches seront exécutées dans un seul thread.

Android: Toast dans un fil


1

Handlerpeut être utilisé avec Threadpour créer un mécanisme en file d'attente. Vous pouvez utiliser le handlerpour publier quelque chose sur leThread Looper


Merci d'avoir pris le temps de répondre à ma question. Pourquoi ne pas utiliser un exécuteur? et même si je voulais utiliser un Handler pour faire ça, comment?
JRun

l'exécuteur testamentaire est un peu différent. Pour l'utiliser, vous devez étendre le thread et appeler le static.metohd prepare.of la classe Looper. après avoir appelé la boucle de méthode statique, une file d'attente est créée et vous pouvez utiliser un ordre handlerbin pour transférer les requêtes et récupérer les résultats
Blackbelt
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.