线程相关问题

186 阅读2分钟

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