2019-07-09:为什么在子线程中创建Handler会抛异常?
Moosphan opened this issue · 9 comments
因为没有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 沐风大佬
Handler 的构造方法中,会通过Looper.myLooper()获取looper对象,如果为空,则抛出异常,主线程则因为已在入口处ActivityThread的main方法中通过 Looper.prepareMainLooper()获取到这个对象,并通过 Looper.loop()开启循环,在子线程中若要使用handler,可先通过Loop.prepare获取到looper对象,并使用Looper.loop()开启循环。
因为代码里就是这样写的
在子线程中创建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