基本元素
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没有消息时候会进入睡眠状态释放线程。
网友评论