Comment afficher un toast à partir d'un fil d'arrière-plan sur Android?

Réponses:

246

Vous pouvez le faire en appelant une Activityde » runOnUiThreadméthode de votre fil:

activity.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});
Lauri Lehtinen
la source
Je ne suis pas sûr de comprendre comment faire cela. J'ai mon vide public existant run (). J'ai essayé de mettre ce code là-bas. Je sais que ce n'est pas juste parce que ça n'a pas marché, mais je suis vraiment coincé.
SwimBikeRun
14
Est-ce que "activité" est passée au thread non-ui dans son constructeur? Quelle est la bonne façon d'obtenir l'objet d'activité que vous utilisez à partir du thread séparé?
snapfractalpop
Définissez la Threadréférence de l' objet à la Activitydans les Activity« s onResume. Désactivez-le dans le Activity's onPause. Faites les deux sous une synchronizedserrure qui respecte Activityet Threadrespecte.
JohnnyLambada
5
parfois il n'y a pas d'accès à l' Activityinstance, vous pouvez utiliser une simple classe d'assistance à la place, voir ici: stackoverflow.com/a/18280318/1891118
Oleksii K.
5
J'ai généralement trouvé que cela MyActivity.this.runOnUiThread()fonctionne très bien depuis un fichier Thread/ AsyncTask.
Anthony Atkinson
62

J'aime avoir une méthode dans mon activité appelée showToastque je peux appeler de n'importe où ...

public void showToast(final String toast)
{
    runOnUiThread(() -> Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show());
}

Je l'appelle alors le plus souvent de l'intérieur MyActivitysur n'importe quel fil comme celui-ci ...

showToast(getString(R.string.MyMessage));
mjaggard
la source
3
Merci, j'ajoute maintenant la plupart des activités.
Gene Myers
1
Pour TOAST, utilisez toujours le contexte d'application, pas le contexte d'activité!
Yousha Aleayoub
1
@YoushaAleayoub pourquoi?
OneWorld
1
@OneWorld, preuves: 1- Pour un message toast, le Guide des développeurs Google utilise le contexte de l'application et dit explicitement de l'utiliser. 2- stackoverflow.com/a/4128799/1429432 3- stackoverflow.com/a/10347346/1429432 4- groups.google.com/d/msg/android-developers/3i8M6-wAIwM/…
Yousha Aleayoub
@YoushaAleayoub Il y a beaucoup de discussions et de devinettes dans les liens que vous avez fournis. Par exemple, RomainGuy dit qu'il n'y a pas de fuite de mémoire dans votre preuve non. 4. Certains des liens datent des débuts d'Android en 2009. Les gens disent également dans les autres liens que vous pouvez utiliser les deux contextes. Activité et application. Peut-être avez-vous une preuve factuelle plus à jour? Avez-vous un lien pour 1?
OneWorld
28

Ceci est similaire à d'autres réponses, mais mis à jour pour les nouveaux apis disponibles et beaucoup plus propre. Aussi, ne suppose pas que vous êtes dans un contexte d'activité.

public class MyService extends AnyContextSubclass {

    public void postToastMessage(final String message) {
        Handler handler = new Handler(Looper.getMainLooper());

        handler.post(new Runnable() {

            @Override
            public void run() {
                Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
            }
        });
    }
}
ChrisCM
la source
Lorsque le contexte que vous avez n'est pas une activité, c'est la réponse parfaite. Merci beaucoup!
francas
17

Une approche qui fonctionne à peu près n'importe où, y compris à partir d'endroits où vous n'avez pas de Activityou View, consiste à attraper un Handlerdans le fil principal et à montrer le toast:

public void toast(final Context context, final String text) {
  Handler handler = new Handler(Looper.getMainLooper());
  handler.post(new Runnable() {
    public void run() {
      Toast.makeText(context, text, Toast.LENGTH_LONG).show();
    }
  });
}

L'avantage de cette approche est qu'elle fonctionne avec tout Context, y compris Serviceet Application.

Mike Laren
la source
10

Comme ceci ou ceci , avec un Runnablequi montre le Toast. À savoir,

Activity activity = // reference to an Activity
// or
View view = // reference to a View

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        showToast(activity);
    }
});
// or
view.post(new Runnable() {
    @Override
    public void run() {
        showToast(view.getContext());
    }
});

private void showToast(Context ctx) {
    Toast.makeText(ctx, "Hi!", Toast.LENGTH_SHORT).show();
}
Yanchenko
la source
6

Parfois, vous devez envoyer un message d'un autre Threadau thread d'interface utilisateur. Ce type de scénario se produit lorsque vous ne pouvez pas exécuter d'opérations réseau / E / S sur le thread d'interface utilisateur.

L'exemple ci-dessous gère ce scénario.

  1. Vous avez un fil d'interface utilisateur
  2. Vous devez démarrer l'opération IO et vous ne pouvez donc pas exécuter Runnablesur le thread d'interface utilisateur. Alors postez votre Runnablegestionnaire surHandlerThread
  3. Récupérez le résultat Runnableet renvoyez-le au fil d'interface utilisateur et affichez un Toastmessage.

Solution:

  1. Créez un HandlerThread et démarrez-le
  2. Créez un gestionnaire avec Looper à partir de HandlerThread:requestHandler
  3. Créer un gestionnaire avec le Looper à partir du thread principal: responseHandleret la handleMessageméthode de substitution
  4. postune Runnabletâche surrequestHandler
  5. A l' intérieur Runnabletâche, appelez sendMessageleresponseHandler
  6. Cet sendMessageappel de résultat de handleMessagein responseHandler.
  7. Obtenez des attributs de Messageet traitez-les, mettez à jour l'interface utilisateur

Exemple de code:

    /* Handler thread */

    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    Handler requestHandler = new Handler(handlerThread.getLooper());

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Runnable on HandlerThread is completed and got result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<5; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {

                    /* Add your business logic here and construct the 
                       Messgae which should be handled in UI thread. For 
                       example sake, just sending a simple Text here*/

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }

Articles utiles:

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

android-looper-handler-handlerthread-i

Ravindra babu
la source
5
  1. Obtenir l'instance du gestionnaire de threads de l'interface utilisateur et l'utiliser handler.sendMessage();
  2. post()Méthode d' appelhandler.post();
  3. runOnUiThread()
  4. view.post()
Kerwin vous
la source
3

Vous pouvez utiliser Looperpour envoyer un Toastmessage. Passez par ce lien pour plus de détails.

public void showToastInThread(final Context context,final String str){
    Looper.prepare();
    MessageQueue queue = Looper.myQueue();
    queue.addIdleHandler(new IdleHandler() {
         int mReqCount = 0;

         @Override
         public boolean queueIdle() {
             if (++mReqCount == 2) {
                  Looper.myLooper().quit();
                  return false;
             } else
                  return true;
         }
    });
    Toast.makeText(context, str,Toast.LENGTH_LONG).show();      
    Looper.loop();
}

et il est appelé dans votre fil. Contexte peut être Activity.getContext()obtient du Activityvous devez montrer le pain grillé.

Vinoj John Hosan
la source
2

J'ai fait cette approche basée sur la réponse de mjaggard:

public static void toastAnywhere(final String text) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        public void run() {
            Toast.makeText(SuperApplication.getInstance().getApplicationContext(), text, 
                    Toast.LENGTH_LONG).show();
        }
    });
}

A bien fonctionné pour moi.

Ângelo Polotto
la source
0

J'ai rencontré le même problème:

E/AndroidRuntime: FATAL EXCEPTION: Thread-4
              Process: com.example.languoguang.welcomeapp, PID: 4724
              java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
                  at android.widget.Toast$TN.<init>(Toast.java:393)
                  at android.widget.Toast.<init>(Toast.java:117)
                  at android.widget.Toast.makeText(Toast.java:280)
                  at android.widget.Toast.makeText(Toast.java:270)
                  at com.example.languoguang.welcomeapp.MainActivity$1.run(MainActivity.java:51)
                  at java.lang.Thread.run(Thread.java:764)
I/Process: Sending signal. PID: 4724 SIG: 9
Application terminated.

Avant: fonction onCreate

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});
thread.start();

Après: fonction onCreate

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});

ça a marché.

Languoguang
la source