Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Can';t在未调用Looper.prepare()的线程内创建处理程序_Android_Ui Thread_Android Toast - Fatal编程技术网

Android Can';t在未调用Looper.prepare()的线程内创建处理程序

Android Can';t在未调用Looper.prepare()的线程内创建处理程序,android,ui-thread,android-toast,Android,Ui Thread,Android Toast,以下例外情况是什么意思;我怎样才能修好它 代码如下: Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT); 这是一个例外: java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序 android.os.Handler.(Handler.java:121) 在android.widget.Toast.(Toast.java:68) 位于and

以下例外情况是什么意思;我怎样才能修好它

代码如下:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
这是一个例外:

java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序
android.os.Handler.(Handler.java:121)
在android.widget.Toast.(Toast.java:68)
位于android.widget.Toast.makeText(Toast.java:231)

您正在从工作线程调用它。您需要从主线程中调用
Toast.makeText()
(以及处理UI的大多数其他函数)。例如,您可以使用处理程序

查阅文档。简言之:

// 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();
}
其他选项:

你可以用。如果您有
活动
,则非常简单:

@WorkerThread
void workerThread(){
myActivity.runOnUiThread(()->{
//这就是您的UI代码所在。
}
}
你也可以发布到主循环器。如果你只有一个
上下文
,这会非常有效

@WorkerThread
void workerThread(){
ContextCompat.getMainExecutor(context.execute)(()->{
//这就是您的UI代码所在。
}
}
已弃用:

您可以使用一个,它对在后台运行的大多数事情都很有效。它有一些钩子,您可以调用这些钩子来指示进度以及何时完成


它很方便,但如果使用不正确,可能会泄漏上下文。它已被正式弃用,您不应该再使用它了。

我遇到了同样的问题,下面是我如何修复它的:

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);
}
要创建UIHandler,您需要执行以下操作:

    HandlerThread uiThread = new HandlerThread("UIHandler");
    uiThread.start();
    uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
class myClass implements IShowMessage{

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

希望这能有所帮助。

ChicoBird的回答对我有效。我唯一做的改变是创建了UIHandler,我必须在其中执行操作

HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse拒绝接受其他任何东西。我想这是有道理的


另外,
uiHandler
显然是一个定义在某个地方的全局类。我仍然不知道安卓是如何做到这一点的,也不知道发生了什么,但我很高兴它能起作用。现在我将继续研究它,看看我是否能理解安卓在做什么,以及为什么要经历所有这些困难和循环。谢谢你的帮助ird.

您需要从UI线程调用
Toast.makeText(…)

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

这是从粘贴的副本。

错误原因:

工作线程用于执行后台任务,除非调用类似runOnUiThread的方法,否则无法在工作线程的UI上显示任何内容。如果尝试在UI线程上显示任何内容而不调用runOnUiThread,则会出现
java.lang.RuntimeException

因此,如果您在一个
活动中
但从工作线程调用
Toast.makeText()
,请执行以下操作:

runOnUiThread(new Runnable() 
{
   public void run() 
   {
      Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();    
   }
}); 
上面的代码确保您在
UI线程中显示Toast消息,因为您在
runOnUiThread
方法中调用它。因此不再
java.lang.RuntimeException
更新-2016 最好的替代方法是使用
RxAndroid
(针对
RxJava
的特定绑定)使
MVP
中的
p
负责数据

首先从您现有的方法返回
可观察的

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

        for (PojoObject pojoObject: pojoObjects) {
            subscriber.onNext(pojoObject);
        }
        subscriber.onCompleted();
    });
}
现在有各种各样的方法来解决这个问题

我将通过代码示例对此进行解释:

runOnUiThread 活套 类用于为线程运行消息循环。默认情况下,线程 没有与之关联的消息循环;要创建一个,请调用 在要运行循环的线程中准备(),然后在 让它处理消息,直到循环停止

异步任务 AsyncTask允许您对用户执行异步工作 接口。它在工作线程和 然后在UI线程上发布结果,而无需 自己处理线程和/或处理程序


当您看到由于在处理程序之前未准备好循环器而导致runtimeException时,请尝试此操作

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

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

我一直在犯这个错误,直到我做了下面的事情

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();
            }
        }
    );
}
并将其制作成一个单例类:

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

}
Toast.makeText()
只能从主/UI线程调用。帮助您实现:

ANDROID

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

此方法的一个优点是可以在没有活动或上下文的情况下使用它。

这是因为Toast.makeText()是从工作线程调用的。它应该像这样从主UI线程调用

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

Toast,AlertDialogs需要在UI线程上运行,您可以在android开发中使用Asynctask来正确使用它们。但在某些情况下,我们需要自定义超时,因此我们使用线程,但在线程中我们不能像在Asynctask中那样使用Toast,AlertDialogs。因此我们需要单独的处理程序用于弹出这些

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();
}
在上面的例子中,我想在3sec中休眠我的线程,然后在mainthreadimplementhandler中显示Toast消息

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

我在这里使用了switch-case,因为如果您需要以相同的方式显示不同的消息,可以在Handler类中使用switch-case…希望这能帮助您在线程中显示对话框或烤面包机,最简洁的方法是使用Activity对象

例如:

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()
...

当我的回调试图显示一个对话框时,我遇到了同样的问题

我使用活动中的专用方法(在活动实例成员级别)解决了这个问题,这些方法使用
runOnUiThread(..)

我就是这么做的

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});
可视组件“锁定”到来自外部线程的更改。 因此,由于toast在主屏幕上显示由主线程管理的内容,因此需要在该线程上运行此代码。
希望有帮助:)

对于Rxjava和RxAndroid用户:

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

我使用以下代码显示来自非主线程“c”的消息
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();
}
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);
       }
};
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()
...
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();
        }
    });
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});
public static void shortToast(String msg) {
    Observable.just(msg)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(message -> {
                Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
            });
}
@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();
    }
}
class myClass implements IShowMessage{

  showMessage("your message!");
 @Override
    public Context getContext() {
        return getApplicationContext();
    }
}
private class MyTask extends AsyncTask<Void, Void, Void> {


@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}
 runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
            }
        });
Handler handler2;  
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
runOnUiThread {
    // Add your ui thread code here
}
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
  }
});
class BootstrapActivity :  CoroutineScope by MainScope() {}
launch {
        // whatever you want to do in the main thread
    }
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
new Handler(Looper.getMainLooper()).post(() -> {
    // Work in the UI thread

}; 
Handler(Looper.getMainLooper()).post{
    // Work in the UI thread
}
CoroutineScope(Job() + Dispatchers.Main).launch {
                        Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
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();
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();