Handler机制原理和常见问题

基本元素

Handler

用于处理消息,包括将发送消息到消息队列,和从消息队列中分发出去。

Message

用户对屏幕操作而产生的信息。

Looper

一个死循环,不停地轮询等待线程给它的消息。

MessageQueue

存放消息的队列,是一个优先级队列,当新插入一个消息的时候,会先和队列内的消息的执行时间做对比,然后插入,执行时间越短,优先级越高,具体方法在enqueueMeassage()方法中。

工作流程

首先可以把整个过程当成一个生产流水线,handler是机器手,message就是产品,messagequeue就是流水线的传输带,handler将message发送到传输带messagequeue上,message按照时间顺序排列在运输袋子上,looper就是发动机带动转轴,把message运输出去,最后又是handler把message分发出去。

具体的方法过程如下:

Handler首先调用sendMessage(),而sendMessage又调用MessageQueue的enqueueMessage()方法,该方法的目的是把message存在消息队列中。

现在消息已经在消息队列中了,需要一个动力去让这些消息被挨个的处理,于是我们就需要looper中的loop函数,它会调用queue.next()方法,这就取到了一个队列中的message,然后handler继续调用dispatchMessage()方法,该方法就包含了handler的handleMessage()方法,然后就会循环该过程。

常见问题

1.Looper如何停下来

当消息队列是空的时候,loop执行queue.next()的时候会阻塞,此时就可以停下来。

2.一个线程中几个handler

随便多少个,new一个有一个。

3.一个线程有几个looper

一个,由threadlocal决定。一个线程里面有一个threadlocalMap类型的变量,里面保存的是threadlocal,所以threadlocal是个key,value键值对,Looper的构造函数是个私有函数,只有在prepare()方法中初始化,在该方法中,set方法会获取当前线程,获取当前threadlocalMap,一个线程只对应一个map,map中一个key对应一个value,key是threadlocal,value就是Looper,所以一个线程绑定一个looper。

4.Handler为什么会内存泄漏,解决方案

Handler持有Activity。因为handler是个匿名内部类,可以持有外部类对象,所以handler持有activity。内存泄漏和handler的机制有关,message持有handler,handler又持有activity,message又有延迟处理的情况,所以会一直存在消息队列中,这时候messageQueue又持有activity,只要message不及时处理,activity就不会被回收。解决方案是:activity弱引用。

5.为什么在主线程中可以直接new handler

当启动app的时候,会先启动Luncher,然后在linux层,会调用zygote去给每个应用建立一个虚拟机,此时会调用activityThread再去使用main方法,里面就有prepareMainLooper方法,此时可以知道所有组件都是围绕主线程looper,以消息存在。

6.怎么在子线程中new一个handler

先Looper.prepare(),在new handler,最后Looper.loop()

7.子消息Looper,没有消息怎么办

消息队列没有消息,会调用nativePollOnce方法,这个方法会进去等待状态,此时会调用linux的epoll函数并传入-1,epoll函数会将结果传入linux的消息队列中,若这个值是-1,则会陷入永久等待状态,线程挂起。

8. Looper怎么退出

调用messageQueue.quit方法,这个过程中,首先removeAllmessageLocked(),把所有的消息全部移出去。此时调用了recycleUnchecked()方法,将消息内部变量赋值为null,然后调用nativeWake(),这个和epoll相反,它唤醒了线程,并返回一个为null的msg,Loop中for循环就会终止。

9.主线程需要释放looper吗

不能,AMS围绕handler管理,四大组件也是靠主线程的Looper处理操作

10.多个handler往消息队列放消息怎么保证线程安全

加锁,使用synchronized

11.怎么生成一个message

使用享元设计模式,提前已经存在了一个消息队列,已经处理完的消息,会被赋值为null,并且用头插法存在这个列表中。当使用obtain的时候会从该消息队列中获取一个空消息

12.Looper为何不会让应用卡死

二者之间,ANR的原因是消息没有被及时处理,而looper没有消息时候会进入睡眠状态释放线程。

你可能感兴趣的:(Handler机制原理和常见问题)