正确姿势理解Handler机制
Handler机制的组成元素:Looper对象、Handler对象、线程
- 线程通过Looper.prepare()方法设置当前线程绑定一个Looper对象
- 紧接着创建一个Handler对象,Handler类会默认设置好Looper对象、MessageQueue,如果在创建Handler对象之前没有调用prepare()方法,就会抛出异常结束程序
- 到此才算是做好了准备工作,值得一提的是主线程会在入口main方法里自动做好准备工作并且还会设置主线程绑定的Looper为主Looper,而一般的线程都是没有默认绑定的Looper对象和默认创建的Handler对象的,详细请自行查阅源码。
- 如果希望尽快理解Handler机制,建议直接理解HandlerThread和Handler的使用,那样你会明白子线程想要轮询消息的时候会分几步做。
Handler机制的原理:消息的发送、传递、处理
消息的发送:
- 通过Handler的sendMessage()发送出去,实际情况却是会通过之前绑定的MessageQueue调用enqueueMessage()并把消息作为参数传入
消息的传递:
- MessageQueue通过调用enqueueMessage()将消息入队之后,然后又因为Looper对象负责MessageQueue的出队,通过调用loop()不断尝试从消息队列中获取消息,直到队列为空。注意了,当队列为空时就是一个死循环。因而此时线程阻塞,同样也是loop(),这个时候由于消息队列不为空取出消息后,会调用dispatchMessage()会回调Handler对象的handleMessage()方法,这个时候便进入了handler对象所在的线程了。
- 但是问题来了,为什么线程阻塞还能sendMessage()?这一点我放在后面解释。
消息的处理:
- 通常在重写handlerMessage()方法利用switch分支实现不同消息对应的不同代码块。
线程阻塞与sendMessage()
- 线程阻塞了是因为loop()对吧,loop()出现在哪里?
- 如果你去查阅一下源码,你会发现,主线程的loop()调用出现在main方法的最后,这意味着什么,当主线程所有操作结束之后才会轮到loop()的死循环,而sendMessage()会将消息入队,loop()获取到不为空的消息后进行一系列分发处理。那么有人问了,线程阻塞了为什么还能调用sendMessage,不应该让出CPU吗?那么你就得了解一下死循环和阻塞了。
死循环VS阻塞
- 死循环会占据cpu,不会被android系统判定为阻塞从而迫使让出cpu的。
- 或者说,真正意义上的阻塞是诸如Wait()、suspend()等这类方法的调用造成的线程阻塞。
- 详情可看以下链接,是一名远古时代的csdn博客作者将一些帖子贴出来的,其中对死循环和阻塞有争论。加油!
- https://blog.csdn.net/zhhxidian2005/article/details/1636695