Handler面试题一:可以在子线程直接new一个Handler吗?那该怎么做?

相关文章:

Handler的工作原理,为什么在子线程中执行 new Handler() 会抛出异常?

正文:

我们先来在子线程中创建一个Handler:

public class MyActivity2 extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Thread("Thread1"){
            @Override
            public void run() {
                super.run();
                Handler handler = new Handler();
            }
        }.start();
    }
}

按说是会报出异常的,但是很奇怪的是,根本没有报出任何异常!!!

下面写的也就不成立了!!

为此,特地新建了一个新项目,但是依然没有报出异常,真是见了鬼了。

放在onCreate()里面是不会报出异常的,如在其他声明周期方法或者点击时间里面,是会报出异常的。

异常如下:

E/AndroidRuntime: FATAL EXCEPTION: Thread1
    Process: com.wzc.chapter_10, PID: 5263
    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:208)
        at android.os.Handler.<init>(Handler.java:122)
        at com.wzc.chapter_10.MyActivity2$1.run(MyActivity2.java:20)

从日志里,可以知道:不能在还没有调用 Looper.prepare() 方法的线程中创建 Handler。 
那我们就在线程中调用一次 Looper.prepare() 方法,再次运行果然不报错了。

Looper.prepare();
Handler handler = new Handler();

但是具体原因是什么?

从 Hander 的构造方法入手:

public Handler() {
        this(null, false);
}

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
 }

在带参的构造函数中,我们发现了抛出异常的地方,在 mLooper 对象为 null 的时候, 会抛出异常。说明这里的 Looper.myLooper();的返回值是 null。 
看一下 Looper.myLooper() 方法:

  public static Looper myLooper() {
        return sThreadLocal.get();
  }

是从 Looper 类 的 sThreadLocal 这个静态成员变量中取出 Looper 对象。 
需要查看一下,sThreadLocal.set() 方法的调用:

  private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
  }

可以看到只有调用了 Looper.prepare() 方法,才会构造一个 Looper 对象并在 ThreadLocal 存储当前线程的 Looper 对象。 
这样在调用 Looper.myLooper() 时,获取的结果就不会为 null

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值