java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

问题重现

在一个回调里,我写了如下代码,

Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                downloadAvatar();
            }
        }, 3000);//3秒后执行

结果抛了运行时异常

E/AndroidRuntime: FATAL EXCEPTION: Timer-2                                                                        
Process: com.purplestoneai.machine, PID: 17296
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:200) at android.os.Handler.<init>(Handler.java:114) at com.purplestoneai.machine.activity.MealActivity$9.uartMsg(MealActivity.java:424)

问题原因

查资料发现了这些信息:Handler对象与它的调用者在同一个线程里。如果在Handler中设置了延时操作,那么它的调用线程也会堵塞。每一个Handler对象都会绑定一个Looper对象,每一个Looper对象对应一个消息队列。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。

在主线程中,可以直接使用new Handler()创建Handler对象,其将自动与主线程的Looper对象绑定;在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程没有开启Looper,而Handler对象必须绑定Looper对象。因此会抛运行时异常。

解决方案

方案1

//开启Looper
Looper.prepare();
//这种情况下,Runnable对象是运行在子线程中的,可以进行联网操作,但是不能更新UI
new Handler().post(new Runnable() {
  @Override
  public void run() {
      try {
           //休眠3秒
           Thread.sleep(3000);
           //doSomething
           downloadAvatar();
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
  }
});
Looper.loop();

方案2

//创建一个绑定在主线程Looper上的句柄
//Looper.getMainLooper()获得主线程的Looper
Handler handler = new Handler(Looper.getMainLooper());
//这种情况下,Runnable对象是运行在主线程中的,不可以进行联网操作,但是可以更新UI
handler.post(new Runnable() {
  @Override
  public void run() {
      try {
          //休眠3秒
          Thread.sleep(3000);
          //doSomething
          downloadAvatar();
      } catch (InterruptedException e) {
          e.printStackTrace();
      } 
  }
});

以上代码均写在回调函数或者某一个子线程中。

需要注意的是,即使代码中没有Handler,也是可能抛这个异常的。比较经常出现的情况是在子线程中直接Toast了。Toast只能在UI线程弹出,如果一定要在子线程中弹,那么需要通过方案2,new一个绑定在主线程Looper上的Handler,在Runnable对象的run方法中Toast。

本文参考了http://www.cnblogs.com/jingmo0319/p/5730963.html

相关文章
相关标签/搜索