¿Cómo se muestra un brindis desde un hilo en segundo plano en Android?

Respuestas:

246

Puede hacerlo llamando a un Activity's runOnUiThreadmétodo de su hilo:

activity.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});
Lauri Lehtinen
fuente
No estoy seguro de entender cómo hacer esto. Tengo mi void público existente run (). Intenté poner este código allí. Sé que eso no está bien porque no funcionó, pero estoy realmente estancado.
SwimBikeRun
14
¿Se pasa la "actividad" al subproceso no ui en su constructor? ¿Cuál es la forma correcta de obtener el objeto de actividad que está utilizando desde dentro del hilo separado?
snapfractalpop
Establezca la Threadreferencia del objeto Activityen el Activity's onResume. Desarmarlo en Activity's onPause. Haz ambas cosas bajo un synchronizedcandado que tanto el Activitycomo el Threadrespeto.
JohnnyLambada
5
a veces no hay acceso a la Activityinstancia, puede usar una clase de ayuda simple en su lugar, consulte aquí: stackoverflow.com/a/18280318/1891118
Oleksii K.
5
Por lo general, he descubierto que MyActivity.this.runOnUiThread()funciona bien desde un interior Thread/ AsyncTask.
Anthony Atkinson
62

Me gusta tener un método en mi actividad llamado al showToastque puedo llamar desde cualquier lugar ...

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

Luego lo llamo con mayor frecuencia desde dentro MyActivityen cualquier hilo como este ...

showToast(getString(R.string.MyMessage));
mjaggard
fuente
3
Gracias, estoy agregando esta mayoría de actividades ahora.
Gene Myers
1
Para TOAST, utilice siempre el contexto de la aplicación, no el contexto de la actividad.
Yousha Aleayoub
1
@YoushaAleayoub ¿por qué?
OneWorld
1
@OneWorld, pruebas: 1- Para un mensaje de brindis, la Guía de desarrollo de Google usa el contexto de la aplicación y explícitamente dice que lo use. 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 Hay mucha discusión y conjeturas en los enlaces que proporcionaste. Por ejemplo, RomainGuy dice que no hay pérdida de memoria en su prueba no. 4. Algunos de los enlaces son de los primeros días de Android en 2009. También la gente dice en los otros enlaces que puedes usar ambos contextos. Actividad y aplicación. ¿Quizás tiene una prueba basada en evidencia real más actualizada? ¿Tiene un enlace para 1?
OneWorld
28

Esto es similar a otras respuestas, sin embargo, actualizado para nuevas apis disponibles y mucho más limpio. Además, no asume que estás en un contexto de actividad.

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
fuente
Cuando el contexto que tienes no es una actividad, esa es la respuesta perfecta. ¡Muchas gracias!
francas
17

Un enfoque que funciona desde prácticamente cualquier lugar, incluso desde lugares donde no tienes una Activityo View, es tomar una Handleral hilo principal y mostrar el brindis:

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

La ventaja de este enfoque es que funciona con cualquiera Context, incluidos Servicey Application.

Mike Laren
fuente
10

Como esto o esto , con un Runnableque muestra el Toast. A saber,

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

A veces, tienes que enviar un mensaje desde otro Threadal hilo de la interfaz de usuario. Este tipo de escenario ocurre cuando no puede ejecutar operaciones de red / IO en el hilo de la interfaz de usuario.

El siguiente ejemplo maneja ese escenario.

  1. Tienes UI Thread
  2. Debe iniciar la operación IO y, por lo tanto, no puede ejecutar Runnableel hilo de la interfaz de usuario. Así que publique su Runnablecontrolador enHandlerThread
  3. Obtenga el resultado de Runnabley envíelo de vuelta al hilo de la interfaz de usuario y muestre un Toastmensaje.

Solución:

  1. Cree un HandlerThread e inícielo
  2. Cree un controlador con Looper desde HandlerThread:requestHandler
  3. Cree un controlador con Looper desde Main Thread: responseHandlery handleMessagemétodo de anulación
  4. postuna Runnabletarea enrequestHandler
  5. Dentro Runnablede tareas, llame sendMessagearesponseHandler
  6. Esta sendMessageinvocación de resultado de handleMessagein responseHandler.
  7. Obtener atributos del Messagey procesarlo, actualizar la interfaz de usuario

Código de muestra:

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

Artículos útiles:

manejarrthreads-y-por-qué-debería-usarlos-en-sus-aplicaciones-de-Android

android-looper-handler-handlerthread-i

Ravindra babu
fuente
5
  1. Obtenga la instancia de UI Thread Handler y use handler.sendMessage();
  2. post()Método de llamadahandler.post();
  3. runOnUiThread()
  4. view.post()
Kerwin usted
fuente
3

Puede utilizar Looperpara enviar un Toastmensaje. Vaya a este enlace para obtener más detalles.

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

y se llama en su hilo. Es posible que el contexto se Activity.getContext()obtenga del Activityque tienes que mostrar el brindis.

Vinoj John Hosan
fuente
2

Hice este enfoque basado en la respuesta 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();
        }
    });
}

Me funcionó bien.

Ângelo Polotto
fuente
0

Encontré el mismo 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: función onCreate

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

Después: función onCreate

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

funcionó.

Languoguang
fuente