消息机制实现_源码分析
2016-05-19 09:10
519 查看
1.主要涉及到三个类MessageQueue,Looper,Handler.附带一个ThreadLocal
其中Looper类为引擎,ThreadLocal保存所有线程创建的Looper实例,以map(key=Thread,value=Looper对象)形式保存
为何Looper类是引擎?因为Looper维护ThreadLocal和MessageQueue(MessageQueue维护Message,Message维护Handler)
线程中使用消息机制:
class LooperThread extends Thread {
public Handler mHandler;
// handler可以在其他线程发送消息给当前线程
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
2.入口1:Looper.prepare();实现
static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// 管理所有Looper对象
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue; // 消息队列
public static void prepare() {
prepare(true);
}
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
// 已经在指定线程创建过Looper对象了
throw new RuntimeException("Only one Looper may be created per thread");
}
// (Thread,Looper对象)键值对形式保存正在ThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
// ThreadLocal的put和get方法之前有分析过
}
3.入口2:mHandler = new Handler()
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) { // 调用new Handler之前必须调用Looper.prepare创建一个Looper对象
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
2.入口3:Looper.loop();实现
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper(); // 获取当前线程Looper对象
final MessageQueue queue = me.mQueue;
...
// 死循环
for (;;) {
// 1.取出消息
Message msg = queue.next(); // might block
// 2.处理消息.调用Message保存的Handler对象的handleMessage方法
msg.target.dispatchMessage(msg);
msg.recycle(); // Return a Message instance to the global pool
}
}
// Handler.java
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 默认为空
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果有设置该回调
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
// 默认有实现该方法,默认调用该方法处理消息
}
}
4.入口4:mHandler.sendMessage实现
Handler.java
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
// 本质:调用消息队列的插入消息的函数
}
5.总结
5.1 消息队列机制引入的原因(实现机制):一个线程中执行完任务后,想执行另外一个线程的某段代码(典型例子:线程执行完耗时操作,想更新UI线程中界面显示)
这个本质上是不能实现的.so想出一种方法,使用一个全局的共享List,里面放各种代码片段(Message中run接口函数),然后A线程死循环查询List中是否有message,如果有取出message,并且执行里面的run代码片段.B线程在执行完任务后,发送message到List中,此时A线程查询到该消息,就取出message的run接口函数,执行里面的函数,从而解决上述问题
其中Looper类为引擎,ThreadLocal保存所有线程创建的Looper实例,以map(key=Thread,value=Looper对象)形式保存
为何Looper类是引擎?因为Looper维护ThreadLocal和MessageQueue(MessageQueue维护Message,Message维护Handler)
线程中使用消息机制:
class LooperThread extends Thread {
public Handler mHandler;
// handler可以在其他线程发送消息给当前线程
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
2.入口1:Looper.prepare();实现
static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// 管理所有Looper对象
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue; // 消息队列
public static void prepare() {
prepare(true);
}
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
// 已经在指定线程创建过Looper对象了
throw new RuntimeException("Only one Looper may be created per thread");
}
// (Thread,Looper对象)键值对形式保存正在ThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
// ThreadLocal的put和get方法之前有分析过
}
3.入口2:mHandler = new Handler()
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) { // 调用new Handler之前必须调用Looper.prepare创建一个Looper对象
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
2.入口3:Looper.loop();实现
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper(); // 获取当前线程Looper对象
final MessageQueue queue = me.mQueue;
...
// 死循环
for (;;) {
// 1.取出消息
Message msg = queue.next(); // might block
// 2.处理消息.调用Message保存的Handler对象的handleMessage方法
msg.target.dispatchMessage(msg);
msg.recycle(); // Return a Message instance to the global pool
}
}
// Handler.java
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 默认为空
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果有设置该回调
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
// 默认有实现该方法,默认调用该方法处理消息
}
}
4.入口4:mHandler.sendMessage实现
Handler.java
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
// 本质:调用消息队列的插入消息的函数
}
5.总结
5.1 消息队列机制引入的原因(实现机制):一个线程中执行完任务后,想执行另外一个线程的某段代码(典型例子:线程执行完耗时操作,想更新UI线程中界面显示)
这个本质上是不能实现的.so想出一种方法,使用一个全局的共享List,里面放各种代码片段(Message中run接口函数),然后A线程死循环查询List中是否有message,如果有取出message,并且执行里面的run代码片段.B线程在执行完任务后,发送message到List中,此时A线程查询到该消息,就取出message的run接口函数,执行里面的函数,从而解决上述问题
相关文章推荐
- oracle数据库高低版本之间导入导出(10g和11g),dmp格式
- css相关
- 我的 2015
- 第五周项目二(2)游戏中的角色类
- 第六次上机实验
- [书目20160519]大未来:移动互联时代的十大趋势
- 在IIS启用MP4
- ValueAnimator实现机制_源码分析
- Web软体安全
- ObjectAnimator实现机制_源码分析
- 我的 2014
- C++实验6-矩阵求和
- Openfire安装报错及启动报错的解决方法探讨
- SpringMVC整合Shiro
- Xcode7.2使用sqlite3数据库的方法
- HTTP状态码(HTTP Status codes)简介
- 每周更新学习进度表--第十一周
- SQL 引用 webservice
- 【原创】CDM添加新磁盘,然后负载
- Choreographer实现机制_源码分析