Handler
Handler 的前世今生
-
为什么要Handler
- 子线程不能操作UI ,用
Handler
从子线程切换到主线程 - 可以共用
Handler
实现异步操作
- 子线程不能操作UI ,用
-
Handler 是什么?
-
Handler
是android
系统里面的一种消息处理机制
-
-
如何使用Handler?
-
可以自己
new
一个Handler
,但是要注意handler
导致的内存泄漏- 把Handler 定义成一个静态内部类
- 在
Activity
或者fragment
关闭时移除 还没有执行的延时消息
通过任何一个view 是不是可以
getHandler
,但是要注意 有可能为空,比如 这个view 的 attacheInfo 为空意思就是这个view 还没有 attach 到 window 上。还可以用过 view 的 psot 方法。只要view 已经 attach 到window 上,底层也是通过Handler 来实现的
-
-
Handler 消息种类?
- 同步消息
- 异步消息
- 屏障消息
-
Handler 如何发送消息?post 和 send 之间的区别
-
可以通过send 和post 两种方式发送:
sendMessage(@NonNull Message msg) sendEmptyMessage(int what) sendEmptyMessageAtTime(int what, long uptimeMillis) sendEmptyMessageDelayed(int what, long delayMillis) sendMessageDelayed(@NonNull Message msg, long delayMillis) sendMessageAtTime(@NonNull Message msg, long uptimeMillis) sendMessageAtFrontOfQueue(@NonNull Message msg) post(@NonNull Runnable r) postAtTime(@NonNull Runnable r, long uptimeMillis) // token 就相当于给这个 Message 打了一个标签,后期可以通过 handler 的 removeCallbacksAndMessages 出入token 对消息进行移除。 postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis) postDelayed(@NonNull Runnable r, long delayMillis) postDelayed(Runnable r, int what, long delayMillis) // app 调用不了 postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis) postAtFrontOfQueue(@NonNull Runnable r) //
上面的所有发送消息的方法(除sendMessageAtFrontOfQueue 以外)最终都会调用到handler 的 一个 叫 sendMessageAtTime(@NonNull Message msg, long uptimeMillis),在这个方法里面 调用
enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis)把消息添加到消息队列里面postAtFrontOfQueue(@NonNull Runnable r) 会调用 sendMessageAtFrontOfQueue 方法,在sendMessageAtFrontOfQueue 里面调用enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis)
总的来说就是 最终调用enqueueMessage 把消息入队,这儿涉及到是三个参数,
1: 队列本身
2:消息本身
3:该消息执行的准确时间。
非延时消息:当前系统时间
延时小时:当前系统时间+你要延时的时间
如果该消息是指明放在队头,那么时间为0
面试如何回答:Handler 可以通过send 和 post 两种方式发送消息,这种两种方式都可以发送即使消息,延时消息,以及直接把消息发送到队列的头部,send 还可以发送空消息,但是不管通过哪种方handler 内部都会封装成一个Message 对象(如果是post 或者发的一个空消息)并且计算出消息执行的确切时间,如果是即使消息,时间就是当前系统时间,如果是延时消息就是当前系统时间+延时的时间,如果是发送到队列头部时间就是0,之所以要计算时间就是因为入队的时候需要通过时间排序,最终调用一个叫enqueueMessage 的方法,在这个方法里面调用队列自己的入队方法,把消息本身和计算出来的时间传递进去进行入队。
-
- Handler 消息如何入队?如何排序?延时消息入队机制?
-
Handler 消息如如何入队和出队?
-
入队:
MessageQueue 实际上是一个链表的的结构,每一个Message 对象里面有一个 next 变量用来指向它的下一个消息。Handler 只负责把消息交给MessageQueue,真正入队的操作时 队列自己完成的,队列在对消息入队时会更具消息执行的时间进行排序,如果队列是空 或者执行时间为0 那么就排在头部,如果头部已经有了,那么内部有一个for 循环 ,从头部该是比较,如果该消息执行的时间小于头部时间 ,那么就插入到头部,然把自己的next 指向原来的头部。如果消息执行的时间大于头部,那么就和后面的挨个比较,直到大于前面并且小于后面,那么就插入到他们中间,如果比到最后一个,发现还是比最后一个大,那么就插入到队列最后一个。
如果发送的消息进过计算后会 插入入到头部,如果发现主线程被阻塞了就会去唤醒,如果没有则不唤醒,入队完成。
-
-
出队:
从队列的头部开始取,如果头部有,用头部消息执行的时间和当前系统时间进行比较,如果执行时间小于 小于等于系统时间,那么该消息满足执行条件,就通过消息找到Handler,然后调用Handler 的 dispatchMessage 方法把消息传给了 Handler,最终调用handler 的 handleMessage 对消息进行处理,如果不满足,那么用消息执行的时间减去系统时间计算出需要等待的时间,然后阻塞在哪儿了,如果中途没有其他人唤醒,到了等待时间后会自动被唤醒。
为什么Handler 能把消息从子线程发送到主线程?
如何在子线程中创建Handler?
为什么UI 线程不会阻塞?
Handler
- 发送消息,
- 处理消息
Looper
1.循环器,循环从消息队列里面取出消息,然后交给handler 处理
Message
- 消息的包装类。里面可以用来传递数据
MessageQueue
1. 消息队列,它是一个假的队列,它本质是一个 链表模拟的队列