Android的Handler机制
- 使用Handler的原因
- Handler4个组成部分解析
- Handler流程:
- 主线程创建Handler实例MHandler
- 子线程中保存创送的消息到message
- 子线程调用MHandler 的sendMessage()
- message添加到MessageQueue
- Looper循环获取message送至Handler的handlerMessage()中处理
1.使用Handler机制的原因
Handler------异步消息处理机制
Android的UI控件是非线程安全的,更新UI必须在主线程中,否则会有异常。但我们需要在子线程中执行一些耗时任务,然后根据任务结果来更新UI。Android中提供了一套消息异步处理机制,完美解决在子线程中进行UI操作的问题。
Handler创建时会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程无Looper,则会报错
- 解决方法:在当前线程创建Looper
- 或者在一个有Looper的线程中创建Looper
4个组成部分:
- Message:线程间传递的消息
- Handler(处理者)
- sendMessage()-----------发送消息
- 消息经过辗转处理,最终会传递给Handler 的 handleMessage(到达主线程)---------处理消息
- MessageQueue:存放Message队列
- Handler的send方法被调用后,它会调用MessageQueue的enqueueMessage方法将这个消息放入消息队列
- 每个线程只有一个MessageQueue
- Looper (消息队列管家):Looper发现有新消息到来时,就会处理这个消息
- loop()
- 每个线程只有一个looper
- 最终消息中的Runnable或者Handler的handleMessage方法就会被调用
- 从而实现线程之间的通信
流程
-
主线程创建一个Handler对象,重写handleMessage()方法
-
(当子线程需要进行UI操作时)
- 创建一个Message对象----保存要传递的消息
- 通过Handler的sendMessage()方法发出消息---------在子线程中获取Handler实例来发送消息
- Handler的post方法将一个Runnable投递到Handler内部的Looper中处理
- 或者通过Handler的send方法发送一个消息,这个消息同样会在Looper中去处理
- post方法最终也是通过send方法发送一个消息
-
这条message被添加到MessageQueue中等待处理
-
- Looper一直尝试从MessageQueue中取出Message
- 并分发会Handler的handleMessage()方法中**(主线程)**----->从而实现线程间通信
消息的延时处理
https://www.jianshu.com/p/edf4f5ee0057/
MessageQueue是按照Message触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。排在越前面的越早触发,那我们现在应该了解到了,这个所谓的延时呢,不是延时发送消息,而是延时去处理消息,我们在发消息都是马上插入到消息队列当中。
可以看到,在这个方法内,如果头部的这个Message是有延迟而且延迟时间没到的(now < msg.when),会计算一下时间(保存为变量nextPollTimeoutMillis),然后在循环开始的时候判断如果这个Message有延迟,就调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞。nativePollOnce()的作用类似与object.wait(),只不过是使用了Native的方法对这个线程精确时间的唤醒。
1、postDelay()一个10秒钟的Runnable A、消息进队,MessageQueue调用nativePollOnce()阻塞,Looper阻塞;
2、紧接着post()一个Runnable B、消息进队,判断现在A时间还没到、正在阻塞,把B插入消息队列的头部(A的前面),然后调用nativeWake()方法唤醒线程;
3、MessageQueue.next()方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;
4、Looper处理完这个消息再次调用next()方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续调用nativePollOnce()阻塞;直到阻塞时间到或者下一次有Message进队;