Handler

2020-08-31  本文已影响0人  资本家大恶人

Handler

target

  1. Handler 的前世今生

  2. 为什么要Handler

    1. 子线程不能操作UI ,用Handler 从子线程切换到主线程
    2. 可以共用Handler 实现异步操作
  3. Handler 是什么?

    1. Handlerandroid 系统里面的一种消息处理机制
  4. 如何使用Handler?

    1. 可以自己 new 一个Handler ,但是要注意 handler 导致的内存泄漏

      1. 把Handler 定义成一个静态内部类
      2. Activity 或者fragment 关闭时移除 还没有执行的延时消息
    2. 通过任何一个view 是不是可以 getHandler,但是要注意 有可能为空,比如 这个view 的 attacheInfo 为空意思就是这个view 还没有 attach 到 window 上。

    3. 还可以用过 view 的 psot 方法。只要view 已经 attach 到window 上,底层也是通过Handler 来实现的

  1. Handler 消息种类?

    1. 同步消息 Wake 线程唤醒

    2. 异步消息(一般发送不了)将屏障消息放在头部消息列队会一直循环♻️直到找到异步消息返回给lopper

    3. 屏障消息 (一般发送不了,服务于异步消息)

  2. Handler 如何发送消息?post 和 send 之间的区别

    1. 可以通过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. 消息队列,它是一个假的队列,它本质是一个 链表模拟的队列



上一篇下一篇

猜你喜欢

热点阅读