从源码角度解析Handler
来源:互联网 发布:网络渗透测试工程师 编辑:程序博客网 时间:2024/06/06 13:25
Handler
一.概述
1.每个Handler都和一个创建它的线程及该线程的MessageQueue关联。
2.handler可以用来发送message和Runnable对象到创建handler的线程的MessageQueue里。
3.handler发送消息的方法有 post, postAtTime(Runnable, long), postDelayed, sendEmptyMessage, sendMessage, sendMessageAtTime, sendMessageDelayed 。
4.主线程默认是有MessageQueue的,而新创建的线程是没有的。
二.handler的使用
1.主线程中:
1.直接在主线程中初始化handler,并重写其handlerMessage方法
2.在非主线程中先获取一个Message对象,可以通过handler.obtainMessage()或直接new一个message对象。然后 使用handler的sendMessage()方法吧该Message对象发送多handler所在的线程。
3.也可以直接调用handler的post()方法把一个Runnable抛到handler所在的线程里执行。
4.不过是发送Message还是post一个Runnable,都可以设置delay时间。
2.工作线程中使用Handler步骤如下:
1.Looper.prepare():初始化MessageQueue和Looper
2.初始化Handler
3.Looper.loop():进行消息循环,这时候加入死循环,loop()下面的代码不会执行;
4.发送消息跟在主线程里的一样。
三.Handler实现原理
1.
子类必须实现的,当有消息来的时候,会回调该函数。
2.
获取消息池里现有的Message,起到对象复用的作用。当然我们也可以自己new一个Message。
3.
很多时候我们创建handler的线程和调用handler的post()方法的线程不是同一个,所以post把一个Runnable任务抛到 handler所在的线程执行。如,我们在UI线程创建了handler,而在自定义线程想修改UI上的一个TextView,我们不能 直接在工作线程里修改,否则会抛出异常,这时候可以创建一个Runnable,在里面修改UI,然后post到handler所在的 线程,即UI 线程。
post方法主要做两件事。1.把Runnable整合为Message,因为Handler只能做Message的消息循环调用。看看getPostMessage ()做了什么:
可以看到,该方法先获取一个Message,然后把Runnable设置为该Message的callback,然后返回该message
然后post方法调用了sendMessageDelayed(),并传进去该message,delay的时间为0
4.接下来看看sendMessageDelayed()方法,该方法直接调用的是sendMessageAtTime(Message,long)
5.
sendMessageAtTime()把message在设定时间入队。对于使用post传递的Message不会回调handleMessage()方法而 是在handler所在的线程自动执行。(见Looper实现原理)
四.Looper实现原理
0.Looper里面有一个ThreadLocal,记录的是当前线程的Looper
1.当调用Looper.prepare()时,调用了重载函数prepare(boolean)
2.prepare(boolean)函数如下
从该函数可以看出,每个线程只能有一个Looper,ThreadLocal保存的是Looper对象。
该函数当Looper在该线程第一次调用时,会创建Looper对象,并添加在该线程的ThreadLocal里。再看看Looper构造 函数:
3.Looper构造函数如下:
该函数创建了一个MessageQueue,并设置了当前线程。
4.当调用Looper.myLooper()时获取的是当前线程的Looper,即当前ThreadLocal里的Looper,所以只有当调用
Looper.prepare()时,ThreadLocal里才有保存当前线程的Looper对象,否则为null。
5.当调用Looper.loop()时开启消息循环
a.可见loop()方法里面是一个死循环,一直从MessageQueue里取出消息,如果MessageQueue当前为空时会阻塞。
如果调用了Looper的quit()方法则MessageQueue会返回null,然后退出死循环结束。
b.当有Message取出来时,把消息发送给Message的所有者
消息的所以者是谁呢?
当我们在其他线程要向handler所在的线程发送Message时,可能会调用handler.obtainMessage()来获取一个Message
(这是对Message对象的复用,也可以new一个Message对象,这时候的消息所有者要看sendMessage()方法)
该方法如下:
再看看Message.obtain(boolean)
obtain(boolean)方法做两步动作,1.获取一个Message对象,然后返回给调用者。2.把该Message的target设置为 调用它的handler,即设置该message的归属者。
c.当Message把消息发送给其所有者后
如果该消息的callback不为空,即在使用handler发送消息是使用的是post发送Runnable的,则调用handleCallback()
该方法直接调用message里callback(Runnable)的run方法。因为该方法是在handler所在的线程调用的,所以run方法 也就是在handler的线程运行。
如果callback为空,即不是通过post发送消息的,则会调用handler的钩子函数handleMessage(Message)。
6.当调用handler的sendMessage(Message)时最后会调用sendMessageAtTime()
该方法会把消息入队。再看看enqueueMessage()
该方法会把Message的target(handler)设置为当前handler,然后把message加入到MessageQueue里。
7.当要终止该线程时,记得终止掉消息循环:
1.调用Looper的quit()方法,该方法是不安全的,它会终止消息循环,并且不保证MessageQueue里剩下的Message 会被执行。当Looper退出之后再想MessageQueue发送消息就会失败。
2.调用Loop人的quitSafely()。该方法是安全的,它会保证MessageQueue里的Message被执行完,但是之后再再 尝试入队会失败。
五.Message实现原理
1.Message的构造函数是public的,所以我们可以直接new一个对象。但是最好的办法是通过Message.obtain()或 Handler.obtainMessage()来获得一个Message对象。因为obtain方法会先从Message对象池里取出可复用的对象,当没有 对象可用时,才会new一个。这样可以起到复用,节省内存的作用。内部实现如下:
1.
Message内部使用单向链表来储存缓存的Message对象。
next:表示链表的下一个Message
sPoolSync:在多线程获取Message对象时加锁用的。
sPool:缓存链表头。
sPoolSize:缓存链表的当前长度。
MAX_POOL_SIZE:最大缓存数。
2.当我们使用Message.obtain()来获取一个Message对象时:
会先从缓存链表里取出来,如果缓存链表里已经为空了则new一个再返回。
2.public int what: 用户可自定义的辨别数据。
3.public int arg1; public int arg2; 如果只是想通过handler传递简单的int数据,可以使用arg1,arg2.
4.public Object obj; 用于传输对象,如果使用Messenger在进程间传输的话,obj对象必需是继承了parcelable 的系统类的对象。
六.Handler与内存泄漏问题
见我之前博客的Android内存篇文章
- 从源码角度解析Handler
- 从源码的角度解析Handler、Looper、Message和MessageQueue
- Handler机制解析(源码角度)
- Handler机制-从源码角度分析
- 从源码角度看Handler原理
- 从源码角度深入理解Handler
- 从源码角度剖析Handler 机制
- 从源码的角度分析Handler机
- 从源码角度剖析Handler机制
- 【Android】从源码角度看Handler机制
- 源码角度解析 Handler 、 Looper 、Message
- Android Handler、Message完全解析,带你从源码的角度彻底理解
- Android Handler、Message完全解析,带你从源码的角度彻底理解
- Android Handler、Message完全解析,带你从源码的角度彻底理解
- Android Handler、Message完全解析,带你从源码的角度彻底理解
- Android Handler、Message完全解析,带你从源码的角度彻底理解
- Android Handler、Message完全解析,带你从源码的角度彻底理解
- 【 Android】handler异步消息处理机制完全解析,带你从源码的角度彻底理解
- 数据恢复设备
- JS正则表达式速查
- Codeforces Round #363 (Div. 2) D DFS
- solidthinking inspire 拓扑优化工具问答-转
- JAVA类获取mybatis的mapper进行数据库操作
- 从源码角度解析Handler
- ios 编译openssl支持arm64
- 码神-day7-java
- Swift UITouch 的使用
- TI C6000DSP上TCP/IP协议栈的实现
- c#计算程序的运行时间
- Java-Enumeration
- 矩形覆盖
- ACM--解析HTML--HDOJ 1088--Write a simple HTML Browser--水