Android-Looper
1个回答
展开全部
Looper.loop是一个死循环,拿不到需要处理的Message就会阻塞,那在UI线程中为什么不会导致ANR?
首先我们来看造成ANR的原因:
1.当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
2.当前的事件正在处理,但没有及时完成
我们再来看一下APP的入口ActivityThread的main方法:
显而易见的,如果main方法中没有looper进行死循环,那么主线程一运行完毕就会退出,会导致直接崩溃,还玩什么!
现在我们知道了消息循环的必要性,那为什么这个死循环不会造成ANR异常呢?
我们知道Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它,这也就是我们为什么不能在UI线程中处理耗时操作的原因。
主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,唤醒主线程,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。
初始化当前线程和Looper,这样可以在实际开始启动循环(loop())之前创建一个Handler并且关联一个looper。确保在先调用这个方法,然后调用loop()方法,并且通过调用quit()结束。
这里面的入参boolean表示Looper是否允许退出,true就表示允许退出,对于false则表示Looper不允许退出。
初始化当前当前线程的looper。并且标记为一个程序的主Looper。由Android环境来创建应用程序的主Looper。因此这个方法不能由咱们来调用。另请参阅prepare()
这里的sThreadLocal.get()是和prepare(boolean)方法里面的sThreadLocal.set(new Looper(quitAllowed));一一对应的。而在prepareMainLooper()方法里面。
退出循环
将终止(loop()方法)而不处理消息队列中的任何更多消息。在调用quit()后,任何尝试去发送消息都是失败的。例如Handler.sendMessage(Message)方法将返回false。因为循环终止之后一些message可能会被无法传递,所以这个方法是不安全的。可以考虑使用quitSafely()方法来确保所有的工作有序地完成。
安全退出循环
调用quitSafely()方法会使循环结束,只要消息队列中已经被传递的所有消息都将被处理。然而,在循环结束之前,将来不会提交处理延迟消息。
调用退出后,所有尝试去发送消息都将失败。就像调用Handler.sendMessage(Message)将返回false。
首先我们来看造成ANR的原因:
1.当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
2.当前的事件正在处理,但没有及时完成
我们再来看一下APP的入口ActivityThread的main方法:
显而易见的,如果main方法中没有looper进行死循环,那么主线程一运行完毕就会退出,会导致直接崩溃,还玩什么!
现在我们知道了消息循环的必要性,那为什么这个死循环不会造成ANR异常呢?
我们知道Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它,这也就是我们为什么不能在UI线程中处理耗时操作的原因。
主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,唤醒主线程,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。
初始化当前线程和Looper,这样可以在实际开始启动循环(loop())之前创建一个Handler并且关联一个looper。确保在先调用这个方法,然后调用loop()方法,并且通过调用quit()结束。
这里面的入参boolean表示Looper是否允许退出,true就表示允许退出,对于false则表示Looper不允许退出。
初始化当前当前线程的looper。并且标记为一个程序的主Looper。由Android环境来创建应用程序的主Looper。因此这个方法不能由咱们来调用。另请参阅prepare()
这里的sThreadLocal.get()是和prepare(boolean)方法里面的sThreadLocal.set(new Looper(quitAllowed));一一对应的。而在prepareMainLooper()方法里面。
退出循环
将终止(loop()方法)而不处理消息队列中的任何更多消息。在调用quit()后,任何尝试去发送消息都是失败的。例如Handler.sendMessage(Message)方法将返回false。因为循环终止之后一些message可能会被无法传递,所以这个方法是不安全的。可以考虑使用quitSafely()方法来确保所有的工作有序地完成。
安全退出循环
调用quitSafely()方法会使循环结束,只要消息队列中已经被传递的所有消息都将被处理。然而,在循环结束之前,将来不会提交处理延迟消息。
调用退出后,所有尝试去发送消息都将失败。就像调用Handler.sendMessage(Message)将返回false。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询