Como você exibe um Toast de um thread de segundo plano no Android?

Respostas:

246

Você pode fazer isso chamando um Activity's runOnUiThreadmétodo de seu segmento:

activity.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});
Lauri Lehtinen
fonte
Não tenho certeza se entendo como fazer isso. Eu tenho meu void público existente executado (). Tentei colocar esse código lá. Eu sei que não está certo porque não funcionou, mas estou realmente preso.
SwimBikeRun
14
A "atividade" é passada para o thread não ui em seu construtor? Qual é a maneira certa de obter o objeto de atividade que você está usando no thread separado?
snapfractalpop
Defina a Threadreferência do objeto como Activityno Activity's onResume. Remova-o no Activity's onPause. Fazer as duas coisas sob um synchronizedbloqueio que tanto o Activitye Threadrespeito.
JohnnyLambada
5
às vezes não há acesso à Activityinstância, você pode usar uma classe auxiliar simples, veja aqui: stackoverflow.com/a/18280318/1891118
Oleksii K.
5
Normalmente descobri que MyActivity.this.runOnUiThread()funciona muito bem dentro de um Thread/ interno AsyncTask.
Anthony Atkinson
61

Gosto de ter um método chamado na minha atividade, showToastque posso chamar de qualquer lugar ...

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

Eu então o chamo mais freqüentemente de dentro MyActivityde qualquer tópico como este ...

showToast(getString(R.string.MyMessage));
mjaggard
fonte
3
Obrigado, estou adicionando a maioria das atividades agora.
Gene Myers
1
Para o TOAST, sempre use o contexto do aplicativo, não o contexto da atividade!
Yousha Aleayoub
1
@YoushaAleayoub por quê?
OneWorld de
1
@OneWorld, provas: 1- Para uma mensagem de brinde, o Guia do desenvolvedor do Google usa o contexto do aplicativo e diz explicitamente para usá-lo. 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 Há muita discussão e suposição nos links que você forneceu. Por exemplo, RomainGuy diz que não há vazamento de memória em sua prova no. 4. Alguns dos links são dos primeiros dias do Android em 2009. Também as pessoas dizem nos outros links que você pode usar os dois contextos. Atividade e aplicação. Talvez você tenha uma prova real baseada em evidências mais atualizada? Você tem um link para 1?
OneWorld de
28

Isso é semelhante a outras respostas, porém atualizadas para novas apis disponíveis e muito mais limpas. Além disso, não presume que você esteja em um Contexto de Atividade.

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
fonte
Quando o contexto que você tem não é uma atividade, essa é a resposta perfeita. Muito obrigado!
francas
17

Uma abordagem que funciona de praticamente qualquer lugar, incluindo de lugares onde você não tem um Activityou View, é pegar um Handlerno tópico principal e mostrar o brinde:

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

A vantagem dessa abordagem é que ela funciona com qualquer um Context, incluindo Servicee Application.

Mike Laren
fonte
10

Como este ou esta , com uma Runnableque mostra a Toast. Nomeadamente,

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
fonte
6

Às vezes, você precisa enviar uma mensagem de outro Threadpara o thread de IU Esse tipo de cenário ocorre quando você não pode executar operações de rede / IO no thread de interface do usuário.

O exemplo abaixo trata desse cenário.

  1. Você tem UI Thread
  2. Você tem que iniciar a operação IO e, portanto, você não pode executar Runnableno thread de IU. Então poste seu Runnablepara manipulador emHandlerThread
  3. Obtenha o resultado Runnablee envie-o de volta ao thread de IU e mostre uma Toastmensagem.

Solução:

  1. Crie um HandlerThread e inicie-o
  2. Crie um Handler com Looper de HandlerThread:requestHandler
  3. Crie um manipulador com Looper do thread principal: responseHandlere handleMessagemétodo de substituição
  4. postuma Runnabletarefa emrequestHandler
  5. Dentro Runnabletarefa, chamada sendMessageemresponseHandler
  6. Esta sendMessageinvocação de resultado de handleMessageem responseHandler.
  7. Obtenha atributos do Messagee processe-os, atualize a IU

Código de amostra:

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

Artigos úteis:

handlerthreads-and-why-you-should-use-them-in-your-android-apps

android-looper-handler-handlerthread-i

Ravindra babu
fonte
5
  1. Obtenha a instância do UI Thread Handler e use handler.sendMessage();
  2. post()Método de chamadahandler.post();
  3. runOnUiThread()
  4. view.post()
Kerwin você
fonte
3

Você pode usar Looperpara enviar Toastmensagem. Vá até este link para mais detalhes.

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

e é chamado em seu tópico. O contexto pode estar Activity.getContext()vindo de Activityvocê tem que mostrar o brinde.

Vinoj John Hosan
fonte
2

Fiz essa abordagem com base na resposta 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();
        }
    });
}

Funcionou bem para mim.

Ângelo Polotto
fonte
0

Eu encontrei o mesmo problema:

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.

Antes: função onCreate

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

Depois: função onCreate

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

funcionou.

Languoguang
fonte