¿Qué significa la siguiente excepción? ¿Cómo puedo arreglarlo?

Este es el código:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

Esta es la excepción:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     at android.os.Handler.<init>(Handler.java:121)
     at android.widget.Toast.<init>(Toast.java:68)
     at android.widget.Toast.makeText(Toast.java:231)
respuesta

Debe llamar Toast.makeText(...)desde el subproceso de la interfaz de usuario:

activity.runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  }
});

Esto se copia y pega de otra respuesta SO (duplicada) .

Lo estás llamando desde un subproceso de trabajo. Debe llamar Toast.makeText()(y la mayoría de las otras funciones relacionadas con la interfaz de usuario) desde el hilo principal. Podrías usar un controlador, por ejemplo.

Busque Comunicarse con el subproceso de interfaz de usuario en la documentación. En una palabra:

// Set this up in the UI thread.

mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
        // This is where you do your work in the UI thread.
        // Your worker tells you in the message what to do.
    }
};

void workerThread() {
    // And this is how you call it from the worker thread:
    Message message = mHandler.obtainMessage(command, parameter);
    message.sendToTarget();
}

Otras opciones:

Podrías usar Activity.runOnUiThread(). Sencillo si tienes un Activity:

@WorkerThread
void workerThread() {
    myActivity.runOnUiThread(() -> {
        // This is where your UI code goes.
    }
}

También puedes publicar en el looper principal. Esto funciona muy bien si todo lo que tienes es un archivo Context.

@WorkerThread
void workerThread() {
    ContextCompat.getMainExecutor(context).execute(()  -> {
        // This is where your UI code goes.
    }
}

Obsoleto:

Podría usar una AsyncTask , que funciona bien para la mayoría de las cosas que se ejecutan en segundo plano. Tiene ganchos a los que puede llamar para indicar el progreso y cuándo ha terminado.

Es conveniente, pero puede filtrar contextos si no se usa correctamente. Está oficialmente en desuso y ya no deberías usarlo.

ACTUALIZACIÓN - 2016

La mejor alternativa es usar RxAndroid(enlaces específicos para RxJava) para que el Pin MVPse haga cargo de los datos.

Comience regresando Observablede su método existente.

private Observable<PojoObject> getObservableItems() {
    return Observable.create(subscriber -> {

        for (PojoObject pojoObject: pojoObjects) {
            subscriber.onNext(pojoObject);
        }
        subscriber.onCompleted();
    });
}

Usa este Observable así:

getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
    @Override
    public void onCompleted() {
        // Print Toast on completion
    }

    @Override
    public void onError(Throwable e) {}

    @Override
    public void onNext(PojoObject pojoObject) {
        // Show Progress
    }
});
}

-------------------------------------------------- -------------------------------------------------- ------------------------------

Sé que llego un poco tarde pero aquí va. Básicamente, Android funciona en dos tipos de subprocesos, a saber, el subproceso de interfaz de usuario y el subproceso de fondo . De acuerdo con la documentación de Android -

Do not access the Android UI toolkit from outside the UI thread to fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:

Activity.runOnUiThread(Runnable)  
View.post(Runnable)  
View.postDelayed(Runnable, long)

Ahora hay varios métodos para resolver este problema.

Lo explicaré por ejemplo de código:

runOnUiThread

new Thread()
{
    public void run()
    {
        myactivity.this.runOnUiThread(new Runnable()
        {
            public void run()
            {
                //Do your UI operations like dialog opening or Toast here
            }
        });
    }
}.start();

LOOPERO

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}

AsyncTask

AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.

public void onClick(View v) {
    new CustomTask().execute((Void[])null);
}


private class CustomTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... param) {
        //Do some work
        return null;
    }

    protected void onPostExecute(Void param) {
        //Print Toast or open dialog
    }
}

Manipulador

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.

Message msg = new Message();


new Thread()
{
    public void run()
    {
        msg.arg1=1;
        handler.sendMessage(msg);
    }
}.start();



Handler handler = new Handler(new Handler.Callback() {

    @Override
    public boolean handleMessage(Message msg) {
        if(msg.arg1==1)
        {
            //Print Toast or open dialog        
        }
        return false;
    }
});

Toast.makeText()solo se puede llamar desde el subproceso principal/UI. Looper.getMainLooper() te ayuda a lograrlo:

JAVA

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
        toast.show();
    }
});

KOTLIN

Handler(Looper.getMainLooper()).post {
        Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT).show()
}

Una ventaja de este método es que puede ejecutar código de interfaz de usuario sin actividad ni contexto.

Intente esto, cuando vea runtimeException debido a que Looper no está preparado antes del controlador.

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

handler.postDelayed(new Runnable() {
  @Override
  public void run() {
  // Run your task here
  }
}, 1000 );

Me encontré con el mismo problema, y ​​así es como lo solucioné:

private final class UIHandler extends Handler
{
    public static final int DISPLAY_UI_TOAST = 0;
    public static final int DISPLAY_UI_DIALOG = 1;

    public UIHandler(Looper looper)
    {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg)
    {
        switch(msg.what)
        {
        case UIHandler.DISPLAY_UI_TOAST:
        {
            Context context = getApplicationContext();
            Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
            t.show();
        }
        case UIHandler.DISPLAY_UI_DIALOG:
            //TBD
        default:
            break;
        }
    }
}

protected void handleUIRequest(String message)
{
    Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
    msg.obj = message;
    uiHandler.sendMessage(msg);
}

Para crear el UIHandler, deberá realizar lo siguiente:

    HandlerThread uiThread = new HandlerThread("UIHandler");
    uiThread.start();
    uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());

Espero que esto ayude.

Motivo de un error:

Los subprocesos de trabajo están destinados a realizar tareas en segundo plano y no puede mostrar nada en la interfaz de usuario dentro de un subproceso de trabajo a menos que llame a un método como runOnUiThread . Si intenta mostrar algo en el subproceso de la interfaz de usuario sin llamar a runOnUiThread, habrá un archivo java.lang.RuntimeException.

Por lo tanto, si está en un hilo activitypero llamando Toast.makeText()desde el trabajador, haga esto:

runOnUiThread(new Runnable() 
{
   public void run() 
   {
      Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();    
   }
}); 

El código anterior asegura que está mostrando el mensaje Toast en un método UI threadya que lo llama dentro . runOnUiThreadAsí que no más java.lang.RuntimeException.

eso fue lo que hice.

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});

Los componentes visuales están "bloqueados" a los cambios de subprocesos externos. Entonces, dado que el brindis muestra cosas en la pantalla principal que son administradas por el subproceso principal, debe ejecutar este código en ese subproceso. Espero que ayude:)

Estaba recibiendo este error hasta que hice lo siguiente.

public void somethingHappened(final Context context)
{
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
            }
        }
    );
}

Y convirtió esto en una clase singleton:

public enum Toaster {
    INSTANCE;

    private final Handler handler = new Handler(Looper.getMainLooper());

    public void postMessage(final String message) {
        handler.post(
            new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
                        .show();
                }
            }
        );
    }

}
 runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
            }
        });

Maravillosa solución de Kotlin:

runOnUiThread {
    // Add your ui thread code here
}

Esto se debe a que Toast.makeText() está llamando desde un subproceso de trabajo. Debería llamarse desde el hilo principal de la interfaz de usuario como este

runOnUiThread(new Runnable() {
      public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
      }
 });

primero llame Looper.prepare()y luego llame a Toast.makeText().show()la última llamada Looper.loop()como:

Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()

La respuesta de ChicoBird funcionó para mí. El único cambio que hice fue en la creación del UIHandler donde tenía que hacer

HandlerThread uiThread = new HandlerThread("UIHandler");

Eclipse se negó a aceptar nada más. Tiene sentido, supongo.

También uiHandleres claramente una clase global definida en alguna parte. Todavía no pretendo entender cómo Android está haciendo esto y qué está pasando, pero me alegro de que funcione. Ahora procederé a estudiarlo y veré si puedo entender qué está haciendo Android y por qué uno tiene que pasar por todos estos aros y bucles. Gracias por la ayuda ChicoBird.

Para usuarios de Rxjava y RxAndroid:

public static void shortToast(String msg) {
    Observable.just(msg)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(message -> {
                Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
            });
}

Me encontraba con el mismo problema cuando mis devoluciones de llamada intentaban mostrar un cuadro de diálogo.

Lo resolví con métodos dedicados en la Actividad, en el nivel de miembro de la instancia de Actividad, que usanrunOnUiThread(..)

public void showAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
        }
    });
}

public void dismissAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
                return;
            }
            mAuthProgressDialog.dismiss();
        }
    });
}

Coroutine lo hará perfectamente

CoroutineScope(Job() + Dispatchers.Main).launch {
                        Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
Handler handler2;  
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());

Ahora handler2 usará un subproceso diferente para manejar los mensajes que el subproceso principal.

Para mostrar un cuadro de diálogo o una tostadora en un hilo, la forma más concisa es usar el objeto Actividad.

Por ejemplo:

new Thread(new Runnable() {
    @Override
    public void run() {
        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
                myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                myActivity.this.processingWaitDialog.setMessage("abc");
                myActivity.this.processingWaitDialog.setIndeterminate(true);
                myActivity.this.processingWaitDialog.show();
            }
        });
        expenseClassify.serverPost(
                new AsyncOperationCallback() {
                    public void operationCompleted(Object sender) {
                        myActivity.runOnUiThread(new Runnable() {
                            public void run() {
                                if (myActivity.this.processingWaitDialog != null 
                                        && myActivity.this.processingWaitDialog.isShowing()) {
                                    myActivity.this.processingWaitDialog.dismiss();
                                    myActivity.this.processingWaitDialog = null;
                                }
                            }
                        }); // .runOnUiThread(new Runnable()
...

Usando lambda:

activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());

Toast , AlertDialogs debe ejecutarse en el subproceso de la interfaz de usuario, puede usar Asynctask para usarlos correctamente en el desarrollo de Android . en AsyncTask . Por lo tanto, necesitamos un controlador separado para las ventanas emergentes.

public void onSigned() {
    Thread thread = new Thread(){
        @Override
        public void run() {
            try{
                sleep(3000);
                Message message = new Message();
                message.what = 2;
                handler.sendMessage(message);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    };
    thread.start();
}

En el ejemplo anterior, quiero suspender mi hilo en 3 segundos y después quiero mostrar un mensaje Toast, para eso en su controlador de implementación de hilo principal.

handler = new Handler() {
       public void handleMessage(Message msg) {
           switch(msg.what){
              case 1:
              Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
              break;
           }
           super.handleMessage(msg);
       }
};

Utilicé switch case aquí, porque si necesita mostrar un mensaje diferente de la misma manera, puede usar switch case dentro de la clase Handler... espero que esto lo ayude.

Esto suele suceder cuando se llama a algo en el subproceso principal desde cualquier subproceso en segundo plano. Veamos un ejemplo, por ejemplo.

private class MyTask extends AsyncTask<Void, Void, Void> {


@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}

En el ejemplo anterior, estamos configurando texto en la vista de texto que se encuentra en el subproceso principal de la interfaz de usuario del método doInBackground(), que opera solo en un subproceso de trabajo.

Tuve el mismo problema y lo solucioné simplemente colocando Toast en la función de anulación de PostExecute() de Asynctask<> y funcionó.

Debe crear un brindis en el subproceso de la interfaz de usuario. Encuentre el ejemplo a continuación.

runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
  }
});

Para mostrar el mensaje Toast, consulte este artículo

Aquí está la solución para Kotlin usando Coroutine:

Amplíe su clase con CoroutineScope de MainScope():

class BootstrapActivity :  CoroutineScope by MainScope() {}

Entonces simplemente haz esto:

launch {
        // whatever you want to do in the main thread
    }

No olvide agregar las dependencias para coroutine:

org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}

Crear controlador fuera del hilo

final Handler handler = new Handler();

        new Thread(new Runnable() {
            @Override
            public void run() {
            try{
                 handler.post(new Runnable() {
                        @Override
                        public void run() {
                            showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
                        }
                    });

                }
            }
            catch (Exception e){
                Log.d("ProvidersNullExp", e.getMessage());
            }
        }
    }).start();

Recientemente, me encontré con este problema: estaba sucediendo porque estaba tratando de llamar a una función que iba a hacer algunas cosas de la interfaz de usuario desde el constructor. Eliminar la inicialización del constructor resolvió el problema para mí.

Java 8

new Handler(Looper.getMainLooper()).post(() -> {
    // Work in the UI thread

}); 

kotlin

Handler(Looper.getMainLooper()).post{
    // Work in the UI thread
}

GL

Tengo el mismo problema y este código funciona bien para mí ahora.
Como ejemplo, este es mi código para realizar una tarea en segundo plano y un subproceso de interfaz de usuario.
Observe cómo se usa el looper:

new Thread(new Runnable() {
    @Override
    public void run() {
    Looper.prepare();
                                
    // your Background Task here

    runOnUiThread(new Runnable() {
        @Override
        public void run() {

        // update your UI here      
                                
        Looper.loop();
        }
    });
    }
}).start();

utilizo el siguiente código para mostrar el mensaje del "contexto" del hilo no principal,

@FunctionalInterface
public interface IShowMessage {
    Context getContext();

    default void showMessage(String message) {
        final Thread mThread = new Thread() {
            @Override
            public void run() {
                try {
                    Looper.prepare();
                    Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
                    Looper.loop();
                } catch (Exception error) {
                    error.printStackTrace();
                    Log.e("IShowMessage", error.getMessage());
                }
            }
        };
        mThread.start();
    }
}

a continuación, utilice como el siguiente:

class myClass implements IShowMessage{

  showMessage("your message!");
 @Override
    public Context getContext() {
        return getApplicationContext();
    }
}