Android-Daily-Interview icon indicating copy to clipboard operation
Android-Daily-Interview copied to clipboard

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

Open Moosphan opened this issue 6 years ago • 9 comments
trafficstars

Moosphan avatar Jul 09 '19 01:07 Moosphan

因为没有looper,需要先prepare

DaveBoy avatar Jul 09 '19 01:07 DaveBoy

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

Vicent9920 avatar Jul 09 '19 01:07 Vicent9920

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

18361237136 avatar Jul 09 '19 06:07 18361237136

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

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

我是小黑 @Moosphan 沐风大佬

yangfanggang avatar Jul 09 '19 09:07 yangfanggang

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

android-ken avatar Jul 09 '19 10:07 android-ken

因为代码里就是这样写的

:octocat: From gitme Android

94kai avatar Jul 11 '19 14:07 94kai

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

hyyaoming avatar Jul 11 '19 16:07 hyyaoming

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

liliangzdh avatar May 14 '20 02:05 liliangzdh

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

mlinqirong avatar Dec 15 '21 03:12 mlinqirong