以下异常是什么意思;我该如何解决?
这是代码:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
这是一个例外:
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)
compile 'com.shamanland:xdroid-toaster:0.0.5'
,它不需要 runOnUiThread()
或 Context
变量,所有例程都消失了!只需调用 Toaster.toast(R.string.my_msg);
这是示例:github.com/shamanland/xdroid-toaster-example
您需要从 UI 线程调用 Toast.makeText(...)
:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
这是从 another (duplicate) SO answer 复制粘贴的。
您从工作线程中调用它。您需要从主线程中调用 Toast.makeText()
(以及大多数其他处理 UI 的函数)。例如,您可以使用处理程序。
在文档中查找 Communicating with the UI Thread。简而言之:
// 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();
}
其他选项:
您可以使用 Activity.runOnUiThread()
。如果您有 Activity
,则直截了当:
@WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
您也可以发布到主循环器。如果您只有一个 Context
,这将非常有用。
@WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
已弃用:
您可以使用 AsyncTask,它适用于在后台运行的大多数事情。它有钩子,您可以调用它来指示进度以及完成时间。
这很方便,但如果使用不当,可能会泄漏上下文。它已被正式弃用,您不应再使用它。
(and most other functions dealing with the UI)
可从后台使用的 UI 函数的一个示例是 android.support.design.widget.Snackbar
- 当不从 UI 线程调用时,它的功能不会减弱。
更新 - 2016
最好的替代方法是为 MVP
中的 P
使用 RxAndroid
(RxJava
的特定绑定)来负责数据。
首先从现有方法返回 Observable
。
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
像这样使用这个 Observable -
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
}
});
}
-------------------------------------------------- -------------------------------------------------- ------------------------------
我知道我来晚了,但我来了。 Android 基本上适用于两种线程类型,即 UI 线程和后台线程。根据android文档-
不要从 UI 线程外部访问 Android UI 工具包来解决此问题,Android 提供了几种从其他线程访问 UI 线程的方法。以下是可以提供帮助的方法列表:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
现在有各种方法可以解决这个问题。
我将通过代码示例进行解释:
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();
循环器
用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环;要创建一个,请在要运行循环的线程中调用 prepare(),然后 loop() 让它处理消息,直到循环停止。
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 允许您在用户界面上执行异步工作。它在工作线程中执行阻塞操作,然后在 UI 线程上发布结果,而无需您自己处理线程和/或处理程序。
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
}
}
处理程序
Handler 允许您发送和处理与线程的 MessageQueue 关联的 Message 和 Runnable 对象。
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;
}
});
runOnUiThread
的示例
View
也有方法 post(Runnable)
和 postDelayed(Runnable, long)
!这么多的处理程序是徒劳的。 :)
Toast.makeText()
只能从 Main/UI 线程调用。 Looper.getMainLooper() 帮助您实现它:
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// write your code here
}
});
科特林
Handler(Looper.getMainLooper()).post {
// write your code here
}
这种方法的一个优点是您可以在没有 Activity 或 Context 的情况下运行 UI 代码。
试试这个,当你看到 runtimeException 由于 Looper 在处理程序之前没有准备好。
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
// Run your task here
}
}, 1000 );
android.os.Handler
我遇到了同样的问题,这是我解决它的方法:
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());
希望这可以帮助。
onCreate method
或 AsyncTask 调用,请您发布整个代码以了解事情的工作原理吗?
uiHandler = new UIHandler(uiThread.getLooper());
吗?
错误原因:
工作线程用于执行后台任务,除非您调用 runOnUiThread 之类的方法,否则您无法在工作线程内的 UI 上显示任何内容。如果您尝试在 UI 线程上显示任何内容而不调用 runOnUiThread,则会出现 java.lang.RuntimeException
。
因此,如果您在 activity
中但从工作线程调用 Toast.makeText()
,请执行以下操作:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
上面的代码确保您在 UI thread
中显示 Toast 消息,因为您在 runOnUiThread
方法中调用它。所以没有更多的java.lang.RuntimeException
。
这就是我所做的。
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast(...);
}
});
视觉组件被“锁定”到来自外部线程的更改。因此,由于 toast 在主屏幕上显示由主线程管理的内容,因此您需要在该线程上运行此代码。希望有帮助:)
在我执行以下操作之前,我收到了这个错误。
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();
}
}
);
}
}
Toaster.INSTANCE.postMessage(ResourceUtils.getString(R.string.blah));
一样使用的便利类(我知道很长!我们稍后减少了它),虽然我有一段时间没有使用 toasts
ApplicationHolder.INSTANCE
的评估结果是什么?
CustomApplication.onCreate()
中设置的CustomApplication
的静态变量,考虑到应用程序总是存在而进程存在,这个上下文可以全局使用
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
runOnUiThread(() -> { Toast toast = Toast.makeText(getApplicationContext(), "Message", Toast.LENGTH_SHORT); toast.show(); });
精彩的 Kotlin 解决方案:
runOnUiThread {
// Add your ui thread code here
}
runOnUiThread
是 Activity 的一部分,即 activity?.runOnUiThread { ... }
先调用 Looper.prepare()
,然后调用 Toast.makeText().show()
最后调用 Looper.loop()
,如:
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
这是因为 Toast.makeText() 是从工作线程调用的。它应该像这样从主 UI 线程调用
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
ChicoBird 的回答对我有用。我所做的唯一更改是创建 UIHandler 我必须做的
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse 拒绝接受其他任何东西。我想是有道理的。
此外,uiHandler
显然是在某处定义的全局类。我仍然没有声称了解 Android 是如何做到这一点以及发生了什么,但我很高兴它可以工作。现在我将继续研究它,看看我是否能理解 Android 在做什么以及为什么必须经历所有这些循环。感谢您的帮助 ChicoBird。
对于 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();
});
}
协程会做的很完美
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
当我的回调尝试显示一个对话框时,我遇到了同样的问题。
我使用 Activity 中的专用方法解决了这个问题 - 在 Activity 实例成员级别 - 使用 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();
}
});
}
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
现在 handler2 将使用与主线程不同的线程来处理消息。
爪哇 8
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
});
科特林
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
总帐
要在线程中显示对话框或烤面包机,最简洁的方法是使用 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()
...
使用 lambda:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
Toast,AlertDialogs 需要运行在 UI 线程上,可以使用 Asynctask 在android开发中正常使用。但是有些情况我们需要自定义超时,所以我们使用 Threads,但是在线程中我们不能使用 Toast,Alertdialogs 像我们使用在 AsyncTask.So 我们需要单独的处理程序来弹出这些。
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();
}
在上面的例子中,我想在 3 秒内让我的线程休眠,并且在我想显示 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...希望这会对您有所帮助
这通常发生在从任何后台线程调用主线程上的某些内容时。例如,让我们看一个例子。
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
在上面的示例中,我们通过 doInBackground() 方法在主 UI 线程中的 textview 上设置文本,该方法仅在工作线程上运行。
我遇到了同样的问题,我只是通过将 Toast 放入 Asynctask<> 的 onPostExecute() 覆盖函数来解决它,并且它起作用了。
您需要在 UI 线程上创建 toast。找到下面的例子。
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
要显示 Toast 消息,请参阅此article
这是 Kotlin 使用 Coroutine 的解决方案:
通过 MainScope() 使用 CoroutineScope 扩展您的类:
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}
launch(Dispatchers.Main) { ... }
。
在线程外创建处理程序
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();
最近,我遇到了这个问题 - 发生这种情况是因为我试图调用一个函数来从构造函数中执行一些 UI 工作。从构造函数中删除初始化为我解决了这个问题。
我遇到了同样的问题,这段代码现在对我来说很好。例如,这是我在后台和 UI 线程中执行任务的代码。观察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();
我使用以下代码显示来自非主线程“上下文”的消息,
@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();
}
}
不定期副业成功案例分享