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

Posted

技术标签:

【中文标题】无法在未调用 Looper.prepare() 的线程内创建处理程序【英文标题】:Can't create handler inside thread which has not called Looper.prepare() 【发布时间】:2011-06-27 22:41:09 【问题描述】:

我有一个活动,其中我有一个课程。

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): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called 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 方法。 This会详细解释这个问题。 Can't create handler inside thread that has not called Looper.prepare()的可能重复 【参考方案1】:

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

您很可能根本不想直接实例化处理程序...无论您的 doInBackground() 实现返回的数据将传递给在 UI 线程上运行的 onPostExecute()

   mActivity = ThisActivity.this; 

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

在出现问题的堆栈跟踪之后添加:

看起来您正在尝试从 GL 渲染线程启动 AsyncTask...不要那样做,因为他们也永远不会 Looper.loop()。 AsyncTasks 真正设计为仅从 UI 线程运行。

破坏性最小的解决方法可能是使用Runnable 调用Activity.runOnUiThread(),以启动您的AsyncTask

【讨论】:

答案完全正确。但是,就我而言,我只需要从我的自定义 FtpUpload AsyncTask 类中删除一些 Toast(尝试在 UI 线程上运行),瞧。 同样的错误出现在我身上我很困惑如何解决它我阅读了描述但不知道如何去做任何人都可以给我代码片段【参考方案2】:

Activity.runOnUiThread() 对我不起作用。我通过这种方式创建了一个常规线程来解决这个问题:

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

并以这种方式从 GL 更新中调用它:

new PullTasksThread().start();

【讨论】:

这个解决方案适用于我从 GL 调用它,但你必须确保你没有在运行方法上调用 Toasts! AsyncTask 无法从 GL 调用它。谢谢! 在替换 AsyncTask 时非常适合我。谢谢!【参考方案3】:

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

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

它的作用是从一个完全不同的线程更新 UI 线程中的进度条,该线程通过 Activity 中声明的处理程序的 post() 方法传递。

希望对你有帮助!

【讨论】:

【参考方案4】:

尝试从 UI 线程运行您的异步任务。当我不这样做时,我遇到了这个问题!

【讨论】:

【参考方案5】:

你以这种方式在后台线程中创建处理程序

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

【讨论】:

不仅解决了问题,而且解释性很强。小问题面团。当Work 完成时,如果需要removeCallbacksquit,结构将如何改变,但未达到延迟。因为工作可能会持续更长的预定义延迟。【参考方案6】:

试试这个

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

【讨论】:

尝试添加一点解释。仅代码答案在 SO 上不太受欢迎。【参考方案7】:

对于所有 Kotlin 爱好者,这里是你的代码

Handler(Looper.getMainLooper()).post 
      // any UI update here

【讨论】:

以上是关于无法在未调用 Looper.prepare() 的线程内创建处理程序的主要内容,如果未能解决你的问题,请参考以下文章

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

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

无法在未调用 Looper.prepare()-Alertdialogbox 的线程内创建处理程序 [重复]

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

原因:无法在未调用 Looper.prepare() 的线程上敬酒

运行时异常“无法在未调用 looper.prepare() 的线程内创建处理程序”