396 votes

Exécution du code dans le thread principal à partir d'un autre thread

Dans un service Android, j'ai créé un ou plusieurs threads pour effectuer certaines tâches en arrière-plan.

J'ai une situation où un thread doit poster une certaine tâche sur la file d'attente des messages du thread principal, par exemple un Runnable .

Y a-t-il un moyen d'obtenir Handler du fil de discussion principal et de poster Message / Runnable à partir de mon autre fil ?

2 votes

Vous pouvez également utiliser le récepteur de radiodiffusion personnalisé.... essayer ma réponse ici, [Récepteur de radiodiffusion interne][1] [1] : stackoverflow.com/a/22541324/1881527

0 votes

Il existe de nombreuses façons de le faire. En dehors de la réponse de David et du commentaire de dzeikei dans sa réponse, (3) vous pouvez utiliser un récepteur de diffusion, ou (4) passer le gestionnaire dans les extras de l'Intent utilisé pour démarrer le service, et ensuite récupérer le gestionnaire du thread principal dans le service en utilisant getIntent().getExtras() .

2 votes

@sazzad-hissain-khan, Pourquoi taguer cette question de 2012 avec des réponses majoritairement en Java avec le tag kotlin ?

698voto

David Wasser Points 23169

NOTE : Cette réponse a reçu tellement d'attention, que je dois la mettre à jour. Depuis que la réponse originale a été postée, le commentaire de @dzeikei a reçu presque autant d'attention que la réponse originale. Voici donc 2 solutions possibles :

1. Si votre fil d'arrière-plan contient une référence à un Context objet :

Assurez-vous que vos threads de travail en arrière-plan ont accès à un objet Contexte (peut être le contexte d'application ou le contexte de service). Il suffit ensuite d'effectuer cette opération dans le fil d'exécution du travailleur d'arrière-plan :

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. Si votre fil d'arrière-plan n'a pas (ou n'a pas besoin de) de Context objet

(suggéré par @dzeikei) :

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

1 votes

Merci David, cela a fonctionné pour moi, une dernière chose si vous pouvez m'aider, si j'étend Handler et impl handleMessage() cela empêcherait-il le thread principal de gérer ses messages ? c'est juste une question par curiosité

2 votes

Non. Si vous sous-classez Handler (ou utiliser Handler.Callback ) votre handleMessage() ne sera appelée QUE pour les messages qui ont été postés à l'aide de votre gestionnaire. Le thread principal utilise un gestionnaire différent pour poster/traiter les messages, il n'y a donc pas de conflit.

215 votes

Je pense que vous n'aurez même pas besoin de contexte si vous utilisez Handler mainHandler = new Handler(Looper.getMainLooper());

162voto

Alexey Vassiliev Points 653

Comme l'a fait remarquer correctement un commentateur ci-dessous, il ne s'agit pas d'une solution générale pour les services, mais seulement pour les fils lancés à partir de votre activité (un service peut être un tel fil, mais tous ne le sont pas). Sur le sujet compliqué de la communication service-activité, veuillez lire toute la section Services de la doc officielle - c'est complexe, il serait donc utile de comprendre les bases : http://developer.Android.com/guide/components/services.html#Notifications

La méthode ci-dessous peut fonctionner dans les cas les plus simples :

Si je comprends bien, vous avez besoin qu'un code soit exécuté dans le thread GUI de l'application (je ne vois pas d'autre thread appelé "main"). Pour cela, il existe une méthode sur Activity :

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Doc : http://developer.Android.com/reference/Android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

J'espère que c'est ce que vous recherchez.

24 votes

L'OP dit qu'il fait tourner les fils dans un Service . Vous ne pouvez pas utiliser runOnUiThread() dans un Service . Cette réponse est trompeuse et ne répond pas à la question posée.

100voto

Hissain Points 880

Versions de Kotlin

Lorsque vous êtes sur une activité puis utiliser

runOnUiThread {
    //code that runs in main
}

Lorsque vous avez un contexte d'activité mContext, puis utiliser

mContext.runOnUiThread {
    //code that runs in main
}

Quand vous êtes dans un endroit où aucun contexte disponible puis utiliser

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}

32voto

tema_man Points 443

Il existe un autre moyen simple, si vous n'avez pas accès au Contexte.

1). Créez un handler à partir du looper principal :

Handler uiHandler = new Handler(Looper.getMainLooper());

2). Implémenter une interface Runnable :

Runnable runnable = new Runnable() { // your code here }

3). Postez votre Runnable dans le uiHandler :

uiHandler.post(runnable);

C'est tout ;-) Amusez-vous bien avec les fils, mais n'oubliez pas de les synchroniser.

31voto

david m lee Points 1

Un bloc de code condensé est le suivant :

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

Il ne s'agit pas de transmettre la référence de l'activité ou de l'application.

Équivalent Kotlin :

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X