java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序;

时间:2021-05-04 20:45:30

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的单线程模型只有两个规则:

  1. Do not block the UI thread
  2. 不要阻止UI线程
  3. Do not access the Android UI toolkit from outside the UI thread
  4. 不要从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的单线程模型只有两个规则:

  1. Do not block the UI thread
  2. 不要阻止UI线程
  3. Do not access the Android UI toolkit from outside the UI thread
  4. 不要从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,则可以正常工作