Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2019-07-09:为什么在子线程中创建Handler会抛异常?

Moosphan opened this issue · comments

2019-07-09:为什么在子线程中创建Handler会抛异常?

因为没有looper,需要先prepare

不能在还没有调用 Looper.prepare() 方法的线程中创建 Handler
因为抛出异常的地方,在 mLooper 对象为null的时候, 会抛出异常。说明这里的Looper.myLooper();的返回值是 null。 只有调用了Looper.prepare()方法,才会构造一个Looper对象并在 ThreadLocal 存储当前线程的 Looper 对象。
这样在调用 Looper.myLooper() 时,获取的结果就不会为 null
链接:Handler的工作原理,为什么在子线程中执行 new Handler() 会抛出异常?

要创建Handler必须有looper,先运行looper.prepare

楼上说的正解,主线程默认执行了looper.prepare方法,此时使用Handler就可以往相信队列中不断进行发送消息和取出消息处理,反之没有执行looper.prepare方法,就会抛出异常,这个在源码中有所体现

所以个人感觉这么提问不是很合理,应该问为什么在子线程中不能直接创建Handler来使用?然后引出主线程默认调用looper.prepare这个会合理一点 个人意见

我是小黑 @Moosphan 沐风大佬

commented

Handler 的构造方法中,会通过Looper.myLooper()获取looper对象,如果为空,则抛出异常,主线程则因为已在入口处ActivityThread的main方法中通过 Looper.prepareMainLooper()获取到这个对象,并通过 Looper.loop()开启循环,在子线程中若要使用handler,可先通过Loop.prepare获取到looper对象,并使用Looper.loop()开启循环。

commented

因为代码里就是这样写的

:octocat: From gitme Android

在子线程中创建handler需要手动创建looper。

亲测 ,在华为 Android p8 Android 8.0 下 子线程 创建 Handler 不会闪退。预估华为做了修改,下次回答:可能在 国内一些手机不会闪退。

楼上的都没有回答到点上 子线程创建Handler会抛出异常的原因是因为在looper里面ThreadLocal sThreadLocal = new ThreadLocal() ThreadLocal 就是为了保存的Looper只能在指定线程中获取Looper 因为子线程创建new Handler()并没有指定Looper 所以它就去获取ActivityThread的main方法中创建的looper 而此时的这个looper 是受线程保护的 所以子线程是无法获取的 因此抛出异常所以在子线程中没有looper 如果需要在子线程中开启handle要手动创建looper