Exécuter du code dans le thread principal d’un autre thread

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

J’ai une situation où le thread doit publier certaines tâches sur la queue des messages du thread principal, par exemple un Runnable .

Existe-t-il un moyen d’obtenir Handler du thread principal et de lui envoyer Message / Runnable depuis mon autre thread?

Merci,

REMARQUE: Cette réponse a reçu tellement d’attention que je dois la mettre à jour. Depuis que la réponse originale a été publié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 thread d’arrière-plan a une référence à un object Context :

Assurez-vous que vos threads de travail d’arrière-plan ont access à un object Context (peut être le contexte d’application ou le contexte de service). Ensuite, faites-le simplement dans le thread de travail 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 thread d’arrière-plan n’a pas (ou n’a pas besoin) d’object de Context

(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); 

Comme l’indique un commentateur ci-dessous, ce n’est pas une solution générale pour les services, mais uniquement pour les threads lancés à partir de votre activité (un service peut être un tel thread, mais pas tous). Sur le sujet compliqué de la communication sur les activités de service, lisez la section complète des services de la documentation officielle – elle 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 vous comprends bien, vous avez besoin de code pour être exécuté dans le thread d’interface graphique de l’application (ne peut penser à rien d’autre appelé “thread principal”). Pour cela, il existe une méthode sur l’ 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.

Il y a un autre moyen simple, si vous n’avez pas access au contexte.

1). Créez un gestionnaire depuis le looper principal:

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

2). Implémenter une interface Runnable:

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

3). Publiez votre Runnable sur le uiHandler:

 uiHandler.post(runnable); 

C’est tout 😉 Amusez-vous avec les discussions, mais n’oubliez pas de les synchroniser.

Si vous exécutez du code dans un thread, par exemple en retardant certaines actions, vous devez appeler runOnUiThread partir du contexte. Par exemple, si votre code se trouve dans la classe MainActivity , utilisez ceci:

 MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { myAction(); } }); 

Si votre méthode peut être appelée à partir de main (thread d’interface utilisateur) ou d’autres threads, vous avez besoin d’une vérification comme:

 public void myMethod() { if( Looper.myLooper() == Looper.getMainLooper() ) { myAction(); } else { } 

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 } }); 

Cela n’implique pas la transmission de la référence d’activité ou de la référence d’application.

Kotlin Equivalent:

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

Une méthode à laquelle je peux penser est la suivante:

1) Laisser l’interface utilisateur au service.
2) Exposez une méthode comme celle ci-dessous par le Binder qui enregistre votre Handler :

 public void registerHandler(Handler handler) { mHandler = handler; } 

3) Dans le thread d’interface utilisateur, appelez la méthode ci-dessus après avoir lié le service:

 mBinder.registerHandler(new Handler()); 

4) Utilisez le gestionnaire du thread du service pour publier votre tâche:

 mHandler.post(runnable); 

HandlerThread est une meilleure option pour les threads Java normaux dans Android.

  1. Créer un HandlerThread et le démarrer
  2. Créez un gestionnaire avec Looper depuis HandlerThread: requestHandler
  3. post une tâche Runnable sur requestHandler

Communication avec l’interface utilisateur de HandlerThread

  1. Créer un Handler avec Looper pour le thread principal: responseHandler et la méthode override handleMessage
  2. Dans la tâche Runnable de l’autre thread ( HandlerThread dans ce cas), appelez sendMessage sur responseHandler
  3. Cet sendMessage résultat sendMessage de handleMessage dans responseHandler .
  4. Obtenir les atsortingbuts du Message et le traiter, mettre à jour l’interface utilisateur

Exemple : Mettez à jour TextView avec les données reçues d’un service Web. Étant donné que le service Web doit être appelé sur les threads autres que l’interface utilisateur, HandlerThread créé pour l’opération réseau. Une fois que vous obtenez le contenu du service Web, envoyez un message à votre gestionnaire de thread principal (UI Thread) et ce dernier doit gérer le message et mettre à jour l’interface utilisateur.

Exemple de code:

 HandlerThread handlerThread = new HandlerThread("NetworkOperation"); handlerThread.start(); Handler requestHandler = new Handler(handlerThread.getLooper()); final Handler responseHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { txtView.setText((Ssortingng) msg.obj); } }; Runnable myRunnable = new Runnable() { @Override public void run() { try { Log.d("Runnable", "Before IO call"); URL page = new URL("http://www.your_web_site.com/fetchData.jsp"); SsortingngBuffer text = new SsortingngBuffer(); HttpURLConnection conn = (HttpURLConnection) page.openConnection(); conn.connect(); InputStreamReader in = new InputStreamReader((InputStream) conn.getContent()); BufferedReader buff = new BufferedReader(in); Ssortingng line; while ((line = buff.readLine()) != null) { text.append(line + "\n"); } Log.d("Runnable", "After IO call:"+ text.toSsortingng()); Message msg = new Message(); msg.obj = text.toSsortingng(); responseHandler.sendMessage(msg); } catch (Exception err) { err.printStackTrace(); } } }; requestHandler.post(myRunnable); 

Articles utiles:

handlerthreads-et-pourquoi-vous-devriez-être-les-utiliser-dans-vos-applications-android

android-looper-handler-handlerthread-i

Suivez cette méthode. De cette façon, vous pouvez simplement mettre à jour l’interface utilisateur à partir d’un thread d’arrière-plan. runOnUiThread fonctionne sur le thread principal (interface utilisateur). Je pense que cet extrait de code est moins complexe et facile, surtout pour les débutants.

 AsyncTask.execute(new Runnable() { @Override public void run() { //code you want to run on the background someCode(); //the code you want to run on main thread MainActivity.this.runOnUiThread(new Runnable() { public void run() { /*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/ executeAfterOperation(); } }); } }); 

dans le cas d’un service

créer un gestionnaire dans le oncreate

  handler = new Handler(); 

alors utilisez-le comme ça

  private void runOnUiThread(Runnable runnable) { handler.post(runnable); } 

Je sais que c’est une vieille question, mais je suis tombé sur un fil de discussion principal que j’utilise à la fois dans Kotlin et dans Java. Ce n’est peut-être pas la meilleure solution pour un service, mais pour appeler quelque chose qui changera l’interface utilisateur à l’intérieur d’un fragment, c’est extrêmement simple et évident.

Java (8):

  getActivity().runOnUiThread(()->{ //your main thread code }); 

Kotlin:

 this.runOnUiThread(()->{ //your main thread code }); 
 public void mainWork() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { //Add Your Code Here } }); } 

Cela peut également fonctionner dans une classe de service sans problème.