I have an Android app running a thread. I want a Toast message to show with a message.
我有一个运行线程的Android应用程序。我想要一条Toast消息来显示消息。
When I do this, I get the below exception:
当我这样做时,我得到以下异常:
Logcat trace:
Logcat跟踪:
FATAL EXCEPTION: Timer-0
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$TN.<init>(Toast.java:322)
at android.widget.Toast.<init>(Toast.java:91)
at android.widget.Toast.makeText(Toast.java:238)
Is there a work around for pushing Toast messages from threads to the User Interface?
是否有解决方案将Toast消息从线程推送到用户界面?
5 个解决方案
#1
108
I got this exception because I was trying to make a Toast popup from a background thread.
Toast needs an Activity to push to the user interface and threads don't have that.
So one workaround is to give the thread a link to the parent Activity and Toast to that.
我得到了这个例外,因为我试图从后台线程制作一个Toast弹出窗口。 Toast需要一个Activity来推送到用户界面,而线程没有。因此,一种解决方法是为线程提供指向父Activity和Toast的链接。
Put this code in the thread where you want to send a Toast message:
将此代码放在要发送Toast消息的线程中:
parent.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
}
});
Keep a link to the parent Activity in the background thread that created this thread. Use parent variable in your thread class:
在创建此线程的后台线程中保留指向父Activity的链接。在线程类中使用父变量:
private static YourActivity parent;
When you create the thread, pass the parent Activity as a parameter through the constructor like this:
创建线程时,通过构造函数将父Activity作为参数传递,如下所示:
public YourBackgroundThread(YourActivity parent) {
this.parent = parent;
}
Now the background thread can push Toast messages to the screen.
现在后台线程可以将Toast消息推送到屏幕。
#2
31
Android basically works on two thread types namely UI thread and background thread. According to android documentation -
Android基本上适用于两种线程类型,即UI线程和后台线程。根据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:
不要从UI线程外部访问Android UI工具包来解决此问题,Android提供了几种从其他线程访问UI线程的方法。以下列出了可以提供帮助的方法:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Now there are various methods to solve this problem. I will explain it by code sample
现在有各种方法可以解决这个问题。我将通过代码示例解释它
runOnUiThread
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
LOOPER
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.
用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环;创建一个,在运行循环的线程中调用prepare(),然后循环()让它处理消息,直到循环停止。
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
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.
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
处理器
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
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;
}
});
#3
6
Here's what I've been doing:
这是我一直在做的事情:
public void displayError(final String errorText) {
Runnable doDisplayError = new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
}
};
messageHandler.post(doDisplayError);
}
That should allow the method to be called from either thread.
这应该允许从任一线程调用该方法。
Where messageHandler is declared in the activity as ..
其中messageHandler在活动中声明为..
Handler messageHandler = new Handler();
#4
6
From http://developer.android.com/guide/components/processes-and-threads.html :
来自http://developer.android.com/guide/components/processes-and-threads.html:
Additionally, the Android UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:
此外,Android UI工具包不是线程安全的。因此,您不能从工作线程操纵UI - 您必须从UI线程对您的用户界面进行所有操作。因此,Android的单线程模型只有两个规则:
- Do not block the UI thread
- 不要阻止UI线程
- Do not access the Android UI toolkit from outside the UI thread
- 不要从UI线程外部访问Android UI工具包
You have to detect idleness in a worker thread and show a toast in the main thread.
您必须检测工作线程中的空闲状态并在主线程中显示Toast。
Please post some code, if you want a more detailed answer.
如果您想要更详细的答案,请发布一些代码。
After code publication :
代码发布后:
In strings.xml
在strings.xml中
<string name="idleness_toast">"You are getting late do it fast"</string>
In YourWorkerThread.java
在YourWorkerThread.java中
Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast),
Toast.LENGTH_LONG).show();
Don't use AlertDialog, make a choice. AlertDialog and Toast are two different things.
不要使用AlertDialog,做出选择。 AlertDialog和Toast是两回事。
#5
1
You can simply use BeginInvokeOnMainThread(). It invokes an Action on the device main (UI) thread.
您可以简单地使用BeginInvokeOnMainThread()。它在设备主(UI)线程上调用Action。
Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });
It is simple and works perfectly for me!
它很简单,对我来说很完美!
EDIT : Works if you're using C# Xamarin
编辑:如果您使用C#Xamarin,则可以正常工作
#1
108
I got this exception because I was trying to make a Toast popup from a background thread.
Toast needs an Activity to push to the user interface and threads don't have that.
So one workaround is to give the thread a link to the parent Activity and Toast to that.
我得到了这个例外,因为我试图从后台线程制作一个Toast弹出窗口。 Toast需要一个Activity来推送到用户界面,而线程没有。因此,一种解决方法是为线程提供指向父Activity和Toast的链接。
Put this code in the thread where you want to send a Toast message:
将此代码放在要发送Toast消息的线程中:
parent.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
}
});
Keep a link to the parent Activity in the background thread that created this thread. Use parent variable in your thread class:
在创建此线程的后台线程中保留指向父Activity的链接。在线程类中使用父变量:
private static YourActivity parent;
When you create the thread, pass the parent Activity as a parameter through the constructor like this:
创建线程时,通过构造函数将父Activity作为参数传递,如下所示:
public YourBackgroundThread(YourActivity parent) {
this.parent = parent;
}
Now the background thread can push Toast messages to the screen.
现在后台线程可以将Toast消息推送到屏幕。
#2
31
Android basically works on two thread types namely UI thread and background thread. According to android documentation -
Android基本上适用于两种线程类型,即UI线程和后台线程。根据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:
不要从UI线程外部访问Android UI工具包来解决此问题,Android提供了几种从其他线程访问UI线程的方法。以下列出了可以提供帮助的方法:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Now there are various methods to solve this problem. I will explain it by code sample
现在有各种方法可以解决这个问题。我将通过代码示例解释它
runOnUiThread
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
LOOPER
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.
用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环;创建一个,在运行循环的线程中调用prepare(),然后循环()让它处理消息,直到循环停止。
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
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.
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
处理器
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
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;
}
});
#3
6
Here's what I've been doing:
这是我一直在做的事情:
public void displayError(final String errorText) {
Runnable doDisplayError = new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
}
};
messageHandler.post(doDisplayError);
}
That should allow the method to be called from either thread.
这应该允许从任一线程调用该方法。
Where messageHandler is declared in the activity as ..
其中messageHandler在活动中声明为..
Handler messageHandler = new Handler();
#4
6
From http://developer.android.com/guide/components/processes-and-threads.html :
来自http://developer.android.com/guide/components/processes-and-threads.html:
Additionally, the Android UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:
此外,Android UI工具包不是线程安全的。因此,您不能从工作线程操纵UI - 您必须从UI线程对您的用户界面进行所有操作。因此,Android的单线程模型只有两个规则:
- Do not block the UI thread
- 不要阻止UI线程
- Do not access the Android UI toolkit from outside the UI thread
- 不要从UI线程外部访问Android UI工具包
You have to detect idleness in a worker thread and show a toast in the main thread.
您必须检测工作线程中的空闲状态并在主线程中显示Toast。
Please post some code, if you want a more detailed answer.
如果您想要更详细的答案,请发布一些代码。
After code publication :
代码发布后:
In strings.xml
在strings.xml中
<string name="idleness_toast">"You are getting late do it fast"</string>
In YourWorkerThread.java
在YourWorkerThread.java中
Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast),
Toast.LENGTH_LONG).show();
Don't use AlertDialog, make a choice. AlertDialog and Toast are two different things.
不要使用AlertDialog,做出选择。 AlertDialog和Toast是两回事。
#5
1
You can simply use BeginInvokeOnMainThread(). It invokes an Action on the device main (UI) thread.
您可以简单地使用BeginInvokeOnMainThread()。它在设备主(UI)线程上调用Action。
Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });
It is simple and works perfectly for me!
它很简单,对我来说很完美!
EDIT : Works if you're using C# Xamarin
编辑:如果您使用C#Xamarin,则可以正常工作