- 讲解原理前先看看Handler一般是如何在activity中使用的,如下为简单的例子
private MyHandler myHandler = new MyHandler();
1.1重写Handler中的handleMessage方法
private class MyHandler extends Handler{
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(),
"[handlerCount]"+(handlerCount++)+"[what]"+msg.what, Toast.LENGTH_SHORT).show();
}
}
1.2在按键点击事件中添加如下代码,即可将what==1的msg发送到MyHandler 中的handleMessage方法中
Message msg = new Message();
msg.setTarget(myHandler);
msg.what =1;
msg.sendToTarget();
或从Message池中获取msg并发送
myHandler.obtainMessage(1).sendToTarget();
- Handler的处理模型是消息驱动,那么也意味着至少包含如下3个组件:循环组件(Looper)、消息(Message)、消息处理组件(Handler->handleMessage),如下给出大致的模型图
MessageQueue组件则对消息(Message)进行了统一的存放并管理,即消息队列
2.1由图可以看出大致步骤如下:
- Handler不断的将消息(Message)放入消息队列(MessageQueue)中
- 循环组件(Looper)不断的从消息队列(MessageQueue)中取出消息(Message)并分发至具体的处理组件(Handler->handleMessage)
2.2从如上步骤中能得出以下问题
- 消息是从何而来的?
- 对于消息的处理是如何循环起来的,即Looper组件从何而来?
- Handler、MessageQueue、Message、Looper之间又是如何建立关系的?
- Looper中又是如何处理MessageQueue中的Message的?
接下来则一一进行解答。
2.3 消息是从何而来的
2.3.1重新实例化一条消息
Message msg = new Message();
msg.setTarget(myHandler);
msg.what =1;
msg.sendToTarget();
2.3.2从Message池中获取Message并发送,如此能提高效率
myHandler.obtainMessage(1).sendToTarget();
2.4 对于消息的处理是如何循环起来的,即Looper组件从何而来
一般情况下,一款应用即代表linux下的一例进程,而包含UI的Activity则运行于该进程下的主线程中。下面看看Activity的onCreate方法是如何被调用的。
在onCreate中添加线程栈打印方法,代码如下
运行后得到如下线程调用栈
从线程栈可以清楚的看到主线程由ZygoteInit启动,经过一系列调用后可以看到我们自己编写的Activity onCreate方法则被ActivityThread的main调用,如下列出重要函数
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
}
Looper的实例化则位于Looper.prepareMainLooper();静态方法中,如下为方法调用关系
由uml图可知,在执行完Looper的prepareMainLooper()静态方法后主线程的循环组件也已实例化,且在Looper的构造方法中实例并关联了消息队列(MessageQueue)的,由此也可以得出如下结论:
- 主线程与Looper是一一对应的,即一个线程中只有一个循环组件(Looper)
- Looper与消息队列(MessageQueue)也是一一对应的,即一个循环组件(Looper)只有一个消息队列(MessageQueue)
其中主线程的Looper被sMainLooper指向,并可通过myLooper()方法进行获取。
2.5 Handler、MessageQueue、Message、Looper之间又是如何建立关系的
2.5.1Handler在实例化Message时指定并关联,代码如下
Message msg = new Message();
msg.setTarget(myHandler);
msg.what =1;
2.5.2 Message与MessageQueue之间的关系建立,实际上仅仅是通过Handler将Message放入Looper中的MessageQueue中的,代码表现为消息(Message)调用sendToTarget方法将自己压入指定Looper的MessageQueue中,代码流程大致如下
其中C1使用的mQueue则是在Looper实例化时指定。
2.5.3 MessageQueue与Looper之间的关系建立,见问题二分析
2.6. Looper中又是如何处理MessageQueue中的Message的
在ActivityThread的main方法中,最终调用Looper.loop()进行message的处理,时序图如下
从时序图中可以看到,loop方法最终将调用Handler中的dispatchMessage来对消息(Message)进行分发
已分析到此,对于消息的具体处理不再进行分析,并向阅读者提出如下两个问题,希望能认真的思考下
2.6.1 对Message的处理,除了重写Handler中的handleMessage方法,还能通过哪些方式?
2.6.2 对Message中消息处理方法的调用优先级又是怎样的?
2.6.3 为何在四大组件中通过Handler()既可以在handleMessage方法对UI控件进行操作?