Handler
target
-
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 消息种类?
-
同步消息 Wake 线程唤醒
-
异步消息(一般发送不了)将屏障消息放在头部消息列队会一直循环♻️直到找到异步消息返回给lopper
-
屏障消息 (一般发送不了,服务于异步消息)
-
-
Handler 如何发送消息?post 和 send 之间的区别
- 可以通过send 和post 两种方式发送:
在Android中handler用来进行进程间bai通信,其中有send和post两种方法du,大家常用的send方法,其是在工作zhi线程中处理完耗dao时操作后调用handler的sendMessage(message)把message对象发送给主线程,在主线程中重写handlerMessage()方法,判断接收到的消息进行更新UI的操作;而post方法传递的是一个runnable对象,更新UI的操作也是在这个runnable的run方法中进行的,也就是说run方法中的代码是执行在主线程中的,虽然它是写在工作线程中,主线程在接收到消息后自动执行runnable的run方法中的代码。
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 的方法,在这个方法里面调用队列自己的入队方法,把消息本身和计算出来的时间传递进去进行入队。
7. Handler 消息如何入队?如何排序?延时消息入队机制?
8. Handler 消息如如何入队和出队?
1. 入队:
MessageQueue 实际上是一个链表的的结构,每一个Message 对象里面有一个 next 变量用来指向它的下一个消息。Handler 只负责把消息交给MessageQueue,真正入队的操作时 队列自己完成的,队列在对消息入队时会更具消息执行的时间进行排序,**如果队列是空** 或者执**行时间为0** 那么就排在头部,如果头部已经有了,那么内部有一个for 循环 ,从头部该是比较,如果该消息**执行的时间小于头部时间** ,那么就插入到头部,然把自己的next 指向原来的头部。如果消息执行的时间大于头部,那么就和后面的挨个比较,直到大于前面并且小于后面,那么就插入到他们中间,如果比到最后一个,发现还是比最后一个大,那么就插入到队列最后一个。
如果发送的消息进过计算后会 插入入到头部,如果发现主线程被阻塞了就会去唤醒,如果没有则不唤醒,入队完成。
2. 出队:
从队列的头部开始取,如果头部有,用头部消息执行的时间和当前系统时间进行比较,如果执行时间小于 小于等于系统时间,那么该消息满足执行条件,就通过消息找到Handler,然后调用Handler 的 dispatchMessage 方法把消息传给了 Handler,最终调用handler 的 handleMessage 对消息进行处理,如果不满足,那么用消息执行的时间减去系统时间计算出需要等待的时间,然后阻塞在哪儿了,如果中途没有其他人唤醒,到了等待时间后会自动被唤醒。
9. 为什么Handler 能把消息从子线程发送到主线程?
10. 如何在子线程中创建Handler?
11. 为什么UI 线程不会阻塞?
Handler
1. 发送消息,
2. 处理消息
Looper
1.循环器,循环从消息队列里面取出消息,然后交给handler 处理
Message
1. 消息的包装类。里面可以用来传递数据
MessageQueue
1. 消息队列,它是一个假的队列,它本质是一个 链表模拟的队列
网友评论