usar - toast make in android
No se puede crear un controlador dentro del hilo que no haya llamado a Looper.prepare() (20)
ACTUALIZACIÓN - 2016
La mejor alternativa es usar RxAndroid
(enlaces específicos para RxJava
) para que la P
en MVP
haga cargo de los datos.
Comience por devolver Observable
desde su método existente.
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
Usa este observable como este:
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 estoy un poco tarde pero aquí va. Básicamente, Android funciona en dos tipos de subprocesos, a saber, subproceso de interfaz de usuario e hilo de fondo Según la documentación de Android -
No acceda al kit de herramientas de la interfaz de usuario de Android desde fuera del subproceso de la interfaz de usuario para solucionar este problema, Android ofrece varias formas de acceder al subproceso de la interfaz de usuario desde otros subprocesos. Aquí hay una lista de métodos que pueden ayudar:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Ahora hay varios métodos para resolver este problema.
Lo explicaré por código de ejemplo:
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();
LOOPER
Clase utilizada para ejecutar un bucle de mensaje para un hilo. Los subprocesos de forma predeterminada no tienen un bucle de mensajes asociado a ellos; para crear uno, llame a prepare () en el subproceso que debe ejecutar el bucle, y luego bucle () para que procese los mensajes hasta que se detenga el bucle.
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 le permite realizar un trabajo asíncrono en su interfaz de usuario. Realiza las operaciones de bloqueo en un subproceso de trabajo y, a continuación, publica los resultados en el subproceso de la interfaz de usuario, sin necesidad de que usted maneje los subprocesos o los manejadores.
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
}
}
Entrenador de animales
Un controlador le permite enviar y procesar objetos Message y Runnable asociados con MessageQueue de un subproceso.
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;
}
});
¿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)
Esto se debe a que Toast.makeText () está llamando desde un subproceso de trabajo. Debe ser llamada 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);
}
});
Esto suele suceder cuando se llama a algo en el hilo principal desde cualquier hilo de fondo. 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 el texto en la vista de texto que se encuentra en el subproceso de la interfaz de usuario principal del método doInBackground (), que opera solo en un subproceso de trabajo.
Intente esto, cuando vea runtimeException debido a Looper no preparado antes del controlador.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@override
void run() {
// Run your task here
}
}, 1000 );
La respuesta de ChicoBird funcionó para mí. El único cambio que hice fue en la creación de UIHandler donde tuve que hacer
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse se negó a aceptar cualquier otra cosa. Tiene sentido, supongo.
También el uiHandler
es claramente una clase global definida en algún lugar. Todavía no pretendo entender cómo está haciendo esto Android 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.
Lo estás llamando desde un hilo de trabajador. Toast.makeText()
llamar a Toast.makeText()
(y a la mayoría de las demás funciones relacionadas con la interfaz de usuario) desde el hilo principal. Podrías usar un manejador, por ejemplo.
Consulte Comunicarse con el hilo de la 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í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 se realiza.
También puede usar Activity.runOnUiThread() .
Me encontré con el mismo problema cuando mis devoluciones de llamada intentaban mostrar un diálogo.
Lo resolví con métodos dedicados en la Actividad, a nivel de miembro de la instancia de la Actividad , que utilizan runOnUiThread(..)
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();
}
});
}
Me encontré con el mismo problema, y aquí es cómo 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.
Para Rxjava y RxAndroid User:
public static void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
});
}
Para mostrar un 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()
...
Primero hay que importar una línea dada.
import android.os.StrictMode;
Y luego, agregue las siguientes líneas en el método onCreate()
de su Actividad:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Recibí 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();
}
}
);
}
E hizo esto en una clase de 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();
}
}
);
}
}
Tuve el mismo problema y lo arreglé simplemente colocando la función de reemplazo de Toast en onPostExecute () de Asynctask <> y funcionó.
Utilizo el siguiente código para mostrar el mensaje desde el subproceso no principal "contexto",
@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();
}
}
luego usar como lo siguiente:
class myClass implements IShowMessage{
showMessage("your message!");
@Override
public Context getContext() {
return getApplicationContext();
}
}
eso fue lo que hice.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast(...);
}
});
Los componentes visuales están "bloqueados" a cambios de hilos externos. Por lo tanto, dado que el brindis muestra cosas en la pantalla principal que está gestionada por el hilo principal, debe ejecutar este código en ese hilo. Espero que ayude:)
Toast.makeText()
debe llamarse desde el hilo principal / UI. Looper.getMainLooper() te ayuda a lograrlo:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
Una ventaja de este método es que también puede usarlo en clases que no sean de Actividad (o sin Contexto).
Toast.makeText(...)
llamar a Toast.makeText(...)
desde el hilo 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) .
Motivo de un error:
Los subprocesos de trabajo están diseñados para 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 al método como runOnUiThread . Si intenta mostrar algo en el subproceso de la IU sin llamar a runOnUiThread, habrá una java.lang.RuntimeException
.
Por lo tanto, si está en una activity
pero está llamando a Toast.makeText()
desde el subproceso de trabajo, haga esto:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
El código anterior garantiza que esté mostrando el mensaje de Toast en un UI thread
ya que lo está llamando dentro del método runOnUiThread
. Así que no hay más java.lang.RuntimeException
.
Toast, AlertDialogs necesita 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 dormir mi hilo en 3seg y después quiero mostrar un mensaje de Toast, para eso en el controlador de implementos de mainthread .
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);
}
};
Usé el caso de cambio aquí, porque si necesita mostrar un mensaje diferente de la misma manera, puede usar el caso de cambio dentro de la clase Handler ... espero que esto le ayude
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});