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


81

我有一个活动,并在那里上了一堂课。

text=new Dynamictext(...);
text.setText("txt");

在我的DynamicText Java中,我有以下代码:

public void setText(String text) {
    this.text=text;
    new asyncCreateText().execute();
    //this.createText(text);
}

//private Handler handler = new Handler();

private class asyncCreateText extends AsyncTask<Void, Void, Void> 
{
    @Override
    protected Void doInBackground(Void... unused) {
        return null;
    }

    @Override
    protected void onPostExecute(Void unused) {

    }
}

我得到:

ERROR / AndroidRuntime(5176):原因:java.lang.RuntimeException:无法在尚未调用Looper.prepare()的线程内创建处理程序

如何处理此错误?

ERROR/AndroidRuntime(5370): java.lang.ExceptionInInitializerError
ERROR/AndroidRuntime(5370):     at com.l.start.DynamicText.setText(DynamicText.java:125)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.initfonts(OpenGLRenderer.java:168)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.init(OpenGLRenderer.java:119)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.onSurfaceChanged(OpenGLRenderer.java:90)
ERROR/AndroidRuntime(5370):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1120)
ERROR/AndroidRuntime(5370):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:975)

ERROR/AndroidRuntime(5370): Caused by: java.lang.RuntimeException: 
    Can't create handler inside thread that has not called Looper.prepare()
ERROR/AndroidRuntime(5370):     at android.os.Handler.<init>(Handler.java:121)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
ERROR/AndroidRuntime(5370):     ... 6 more

您可以发布完整的堆栈跟踪信息吗?您似乎正在从后台线程中调用某些UI方法。
alexanderblom

1
将详细解释该问题。
mjosh 2013年

Answers:


146

该错误是不言自明的...doInBackground()在后台线程上运行,由于该线程不旨在循环,因此未连接到Looper

您很可能根本不想直接实例化Handler ...您的doInBackground()实现返回的任何数据都将传递给onPostExecute()在UI线程上运行的数据。

   mActivity = ThisActivity.this; 

    mActivity.runOnUiThread(new Runnable() {
     public void run() {
     new asyncCreateText().execute();
     }
   });

在出现以下堆栈痕迹后添加:

看起来您正在尝试AsyncTask从GL渲染线程开始...不要这样做,因为它们也永远Looper.loop()不会。AsyncTasks实际上是设计为只能从UI线程运行。

破坏性最小的修复方法可能是Activity.runOnUiThread()使用Runnable来启动您的AsyncTask


1
答案是完全正确的。但是,就我而言,我只需要从自定义FtpUpload AsyncTask类和voila中删除一些Toast(尝试在UI线程上运行)。
2014年

同样的错误即将来临,我很困惑如何解决它,但我却看不懂如何做,但是任何人都可以给我代码最简洁的方法吗
Android对我来说就是一切

32

以上所有答案都是正确的,但我认为这是最简单的示例:

public class ExampleActivity extends Activity {
    private Handler handler;
    private ProgressBar progress;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        progress = (ProgressBar) findViewById(R.id.progressBar1);
        handler = new Handler();
    }

    public void clickAButton(View view) {
        // Do something that takes a while
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                handler.post(new Runnable() { // This thread runs in the UI
                    @Override
                    public void run() {
                        progress.setProgress("anything"); // Update the UI
                    }
                });
            }
        };
        new Thread(runnable).start();
    }
}

这样做是通过通过活动中声明的处理程序的post()方法传递的完全不同的线程来更新UI线程中的进度条。

希望能帮助到你!


22

您可以通过这种方式在后台线程中创建处理程序

private void createHandler() {
        Thread thread = new Thread() {
          public void run() {
               Looper.prepare();

               final Handler handler = new Handler();
               handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       // Do Work
                        handler.removeCallbacks(this);
                        Looper.myLooper().quit();
                   }
                }, 2000);

                Looper.loop();
            }
        };
        thread.start();
    }

不仅解决了问题,而且很有解释性。有点问题的面团。如果需要removeCallbacksquit何时Work完成结构的更改,但不会延迟。因为工作可能会持续更长的预定义延迟。
Farid

12

Activity.runOnUiThread()对我不起作用。我通过以下方式创建常规线程来解决此问题:

public class PullTasksThread extends Thread {
   public void run () {
      Log.d(Prefs.TAG, "Thread run...");
   }
}

并从GL调用此更新:

new PullTasksThread().start();

这个解决方案对我来说是从GL调用的,但是您必须确保没有在运行方法上调用Toasts!AsyncTask无法从GL调用它。谢谢!
Alberto M.

对我而言,替换AsyncTask非常有用。谢谢!
IgorGanapolsky

5

尝试从UI线程运行asyntask。我没有做同样的事情时就遇到了这个问题!


3

试试这个

    Handler mHandler = new Handler(Looper.getMainLooper());
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
 //your code here that talks with the UI level widgets/ try to access the UI 
//elements from this block because this piece of snippet will run in the UI/MainThread.                                     
                            }
                        });

1
尝试添加一点解释。在SO上,仅代码答案不是很欣赏。
阿列克谢
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.