Handler
来源:互联网 发布:迪联软件 编辑:程序博客网 时间:2024/06/07 04:58
问题:
- Handler是什么?作用是什么?
- Handler、Loop、MessageQueue、Thread各自的作用,和他们之间的关系。
- 多个Handler实例发送消息时,为什么是当前Handler收到,而不是其他Handler收到
- Looper.loop()为什么不阻塞主线程
- 绘制、点击、Activit生命周期和Handler的关系
- Handler.post()、Handler.handleMessage分别执行在什么线程
- Message是如何发送的。
- Handler导致如何Activity泄漏
- HandlerThread 有什么作用## handler是什么? 作用是什么?我们讲Handler、Loop、MessageQueue等类的时候,最需要思考的一个问题是这些类是什么,作用是什么?
是什么?
个人理解,Handler系列类可以看成是简单的Java类,遵循java的运行时标准。
Handler可以认为是生产者、消费者模式中的生产者。Loop为消费者。MessageQueue是产品库存。
当这一套机制运用到android的GUI中时,就代表了我们所熟知的应用的主线程。当然,这一套机制也可以用于需要循环处理消息的地方。可以在源码中搜索Looper.prepare()方法,可发现android系统中还有97处使用这种方式来进行消息的生产与消费。

作用?
发送消息。
网上有说可以用于线程运行,个人觉得这个描述不准确,可以由如下源码得知,发送的Runnable也是被封装为消息由Looper消费掉的。
Handler.java
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}
重点看下getPostMessage()方法
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}
接着看下消费Message的地方:Looper.loop()放方法。
public static void loop() { //删除了许多不是主要逻辑的代码 for (;;) { Message msg = queue.next(); // might block msg.target.dispatchMessage(msg); msg.recycleUnchecked(); }}
Message 的消费又被传递给生成Message的Handler.dispatchMessage()方法。
public void dispatchMessage(Message msg) { if(msg.callback != null) { handleCallback(msg); } else { if(this.mCallback != null && this.mCallback.handleMessage(msg)) { return; } this.handleMessage(msg); }}
Handler、Loop、MessageQueue、Thread各自的作用,和他们之间的关系。
由上面的代码分析,克制:从整个调用链来看,发送一个消息可以总结为:Handler发送消息,消息被存储到MessageQueue中,由Looper.loop()方法循环查询MessageQueue的队列,获取消息,并把消息分发给Handler自己处理。
职责划分:
Handler:发送消息,处理消息。
MessageQueue:缓存消息,并对消息按照时间轴排序
Looper:分发消息。Looper是一个死循环,需要在某个线程中调用,来完成常驻功能。
可以看下三者的关系图(图片来自经典随机Crash之二:Android消息机制
):

多个Handler实例发送消息时,为什么是当前Handler收到,而不是其他Handler收到
回答这个问题很好解决,只需要进入Hnadler类,的任意一个send*方法,一直往下跟,会发现,追踪都会调用到enqueueMessage()方法。会看到Message会把this赋值给Message.target。this就是Handler对象自己。如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis{ msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
在来看Looper.loop()方法,会调用Message.target.dispatchMessage()方法,并把Message当做参数传递。
public static void loop() { //删除了许多不是主要逻辑的代码 for (;;) { Message msg = queue.next(); // might block msg.target.dispatchMessage(msg); msg.recycleUnchecked(); }}
所以Handler发送消息时,百分百肯定是自己收到。
Looper.loop()为什么不阻塞主线程
我们把Looper作为一个普通的java类的方法来看到时,Looper.loop()方法会阻塞任何调用这个方法的方法所运行的线程。若在主线程中调用肯定也会阻塞掉主线程。
绘制、点击、Activit生命周期和Handler的关系
做过android的都知道,绘制、点击、activity生命周期都是在主线程中完成。即在ACtivityThread.java的Main方法调用的那个Looper中完成。
要说清楚这个问题,需要大幅的篇幅来说明,这里就不在做详细的描述。
与Handler的关系就是在穿件Handler时,使用的Looper为getMainLooper()获取的Looper。
主线程的Handler创建流程:
public static void main(String[] args) { //现在Main线程中穿件一个looper。 Looper.prepareMainLooper(); //由于ThreadLocal.java使用的原理,创建的的Handler使用Looper及时Main线程的Looper。 ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");}
可以看到,使用的Handler是ActivityThread内部的一个Handler
Handler.post()、Handler.handleMessage分别执行在什么线程
Handler.post()执行在什么线程?
这是个伪命题。java方法当然执行在调用他的线程。Handler.handleMessage执行在什么线程。
public static void loop() {
//删除了许多不是主要逻辑的代码
for (;;) {
Message msg = queue.next(); // might block
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
通过loop方法可以看出,Handler.handleMessage会在Looper.loop()方法中调用。
所以是执行在调用Looper.prepare()方法的线程。
所以主线程中new 的Handler,执行在主线程。
Message是如何发送的。
如下图(经典随机Crash之二:Android消息机制):

Handler导致如何Activity泄漏
View.postDelayed(new Runnable() { @Override public void run() { //延迟执行的方法 } }, time);
当使用Handler.postDelayed()方法时,Message会延迟一个time
再执行。使用内部类的Runable会持有当前Activity的对象。当Activity.onDestory()方法执行后,Activity应该被销毁,但此时Activity还被Runable内部内持有,就会导致内存泄漏。
注意:
当此时Activity销毁时,time时间到,调用Activity中的某些方法,会导致crash。 详细可参看:经典随机Crash之二:Android消息机制
HandlerThread 有什么作用
HandlerThread 作用只需要看run()
方法就够了。
可以看到调用HandlerThread.start()
方法后,就会执行run()方法。此时就会进入Loop的死循环。完成有Looper.loop()方法完成消息的分发、执行
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1;}
参考
安卓基础:Handler
ThreadLocal 类说明
经典随机Crash之二:Android消息机制
- Handler
- Handler
- Handler
- handler
- handler
- Handler
- Handler
- Handler
- Handler
- Handler
- Handler
- handler
- Handler
- handler
- handler
- Handler
- Handler
- Handler
- Cg Programming/Unity
- CVE-2012-0158浅析-word栈溢出漏洞
- 解决MDK5在调试中崩溃,提示“IDE已停止工作”的一种方法
- Java双缓冲队列实现
- Android异步下载图片并且缓存图片到本地
- Handler
- ICE的使用
- UITableView拖动时计算页码 & 往上拖拉时自动加载
- MySQL提示:The server quit without updating PID file问题的解决办法
- nyoj 104最大和
- 调用Metasploit RestFul接口,解决证书问题
- linux下查看mysql启动状态
- 条件熵的定义
- kibana插件开发