Can't create handler inside thread that has not called Looper.prepare()
现象:报错Can't create handler inside thread that has not called Looper.prepare()
原因:在子线程中new Handler(加Toast也有这个问题)导致的
分析:因为Handler与其调用者在同一线程中,Handler中执行了延迟操作,会导致调用的线程阻塞。每个Hander对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue),若在创建Handler时不指定与其绑定的Looper对象则默认将当前线程的Looper绑定到该Handler上。
在主线程中直接使用new Hanlder()创建Handler对象,其将自动与主线程的Looper对象绑定;在子线程中直接new创建会报错,因为子线程中没有开启Looper,而Handler对象必须绑定Looper对象。
解决:
方案一:需先在该子线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上。
final Runnable runnable = new Runnable(){
@Override
public void run(){
//执行耗时操作
try{
Log.e("bm", "runnable线程:"+ Thread.currentThread().getId() + " name:" + Thread.currentThread().getName());
Thread.sleep(2000L);
Log.e("bm", "执行完耗时操作了~");
} catch (InterruptedException e){
e.printStackTrace();
}
}
};
new Thread(){
public void run(){
Looper.prepare();
new Handler().post(runnable);//在子线程中直接去new一个handler
Looper.loop();//这种情况下,Runnable对象时运行在子线程中的,可以进行耗时操作,但是不能更新UI
}
}.start();
方案二:通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。
final Runnable runnable = new Runnable() {
  @Override
  public void run() {
    //执行耗时操作
    try {
      Log.e("bm", "runnable线程: " + Thread.currentThread().getId()+ " name:" + Thread.currentThread().getName());
      Thread.sleep(2000);
      Log.e("bm", "执行完耗时操作了~");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
};
new Thread() {
  public void run() {
    new Handler(Looper.getMainLooper()).post(runnable);//在子线程中直接去new 一个handler
    //这种情况下,Runnable对象是运行在主线程中的,不可以进行联网操作,但是可以更新UI
  }
}.start();