在开始这篇文章之前,。首先,我们在总结前两篇文章Handler, Looper和MessageQueue像一些关键点:

0)在创建线程Handler之前,你必须调用Looper.prepare(), 创建一个线程局部变量Looper,然后调用Looper.loop() 进入轮循。

1)当Handler创建之后,就能够调用Handler的sendMessageAtTime方法发送消息。而实际上是调用MessageQueue的enqueueMessage方法。将相应的消息放入消息队列。

2)每个线程都仅仅有一个Looper,这个Looper负责对MessageQueue进行轮循,当获取到Message。就调用handler.dispatchMessage进行分发。

从上面这三点,我们就能够大概地看出Handler的使用流程了。

今天我们就先从消息開始的地方讲起。就是Handler的 enqueueMessage 方法了,代码例如以下:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

此方法主要做了两件事:

1)将msg.target 设置成当前Handler对象

2)调用MessageQueue的enqueueMessage方法

所以。事实上就是在这里。将Message对象放到消息队列中去的。

说到MessageQueue,我们首先要明确这个消息队列事实上是一个链表的结构,一个串一个的。

而其队列的初始化并非在 java层做的。而是在JNI层利用C++实现的。

我们能够看看其定义的几个native方法,例如以下:

    private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native static void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
private native static boolean nativeIsIdling(long ptr);

而其构造函数例如以下:

    MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

在这里,我们并不进入其在JNI层的代码,水太深了。

我们还是从Java层来看吧。在MessageEnqueue的 enqueueMesage方法中。基本的代码例如以下:

synchronized (this) {
...
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
} ...
}

上面是入队列的关键代码,而其所做的操作无非就是依据 when 字段。将消息插入队列中的合适位置。

既然消息已经放到队列中去了。那么下一步就是在Looper的轮循操作中去获取消息,然后将消息进行分发。我们能够在Looper 的loop方法中看到其调用了MessageQueue的next方法。

        for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
} // This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
} msg.target.dispatchMessage(msg);

那么非常显然。就是在MessageQueue的next方法中,获取消息了,让我们也进去其方法看一下吧。

Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
} // We can assume mPtr != 0 because the loop is obviously still running.
// The looper will not call this method after the loop quits.
nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
} // Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
} // If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
} if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
} // Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
} if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
} // Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}

整个的代码有点长,可是我们去掉一些对我们了解实现关系不大的代码,就能够看到主要有下面几点:

1)是一个 for(;;)循环

2)仅仅有当获取 message的时候或者mQuitting为true的时候才会跳出循环。

3)在获取消息的时候,会依据 Message.when 字段来进行推断

从以上几点,我们就能够大概了解为什么说在 loop方法中,next方法有可能会堵塞。由于它就是一个无限的轮循操作呀。

好吧,到这里之后,我们大概知道了下面两件事情:

1)在Handler的sendMessageAtTime方法调用MessageQueue的 enqueueMessage方法,将消息放入队列。

2)在Looper的looop方法。调用MessageQueue的next方法。将消息取出队列。

接下来第三步,非常显然,就是调用handler的dispatchMessage方法了,例如以下:

msg.target.dispatchMessage(msg);

在文章的一開始,我们就注意到了msg.target 正好就是 handler对象,于是逻辑又来到了Handler的dispatchMessage方法,例如以下:

    public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

从代码的逻辑来看,我们须要了解一下几个变量方法都是要什么了:

1)msg.callback

2)  mCallback

3 ) handleMessage

首先, msg.callback是什么?

在Message类中。我们能够看到

Runnable callback;

还有其构造函数:

    public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback; return m;
}

事实上就是一个Runnable变量,能够放到一个新的线程中去跑。能够在获取Message的时候自己定义设置。

所以在dispatchMessage中,首先就是推断是否有对Message设置了Runnable的callback,假设有。就运行这个callback方法,例如以下:

    private static void handleCallback(Message message) {
message.callback.run();
}

那么,第二个mCallback又是什么呢,它事实上上是Handler内置的一个接口,例如以下:

    public interface Callback {
public boolean handleMessage(Message msg);
}

假设有我们的 Handler有实现这个接口,那么当分发消息的时候,此接口就会优先处理消息。

而普通情况下,仅仅有我们想去继承Handler类。实现自己定义的Handler的时候,我们才会去实现这个接口,而当此接口返回true的时候,Handler默认的handleMessage方法就不会再被调用了。反之,则依旧会调用。

最后,就是我们最普通的handleMessage方法了。也就是我们在实现一个最普通的handler的时候所实现的方法了。

相同。没有样例怎么能够呢,请看代码:

    class LooperThread extends Thread {
public Handler mHandler; public void run() {
Looper.prepare(); mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId());
switch (msg.what) {
case MSG_ID_1:
Log.v("Test", "Toast called from Handler.sendMessage()");
break;
case MSG_ID_2:
String str = (String) msg.obj;
Log.v("Test", str);
break;
}
}
};
Looper.loop();
}
} protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); LooperThread looperThread = new LooperThread();
looperThread.start(); while(looperThread.mHandler == null){
} Message message = Message.obtain(looperThread.mHandler, new Runnable() { @Override
public void run() {
Log.v("Test", "Message.callack()");
}
});
message.what = MSG_ID_1;
message.sendToTarget(); looperThread.mHandler.post(new Runnable() { @Override
public void run() {
Log.v("Test", "Handler.callack()");
}
}); }

在这里。我们利用Message.obtain(Handler, Runnable)  方法和Handler.post方法来构造和发送消息,得到的结果例如以下:

10-28 11:27:49.328: V/Test(22009): Id of MainThread : 1
10-28 11:27:49.328: V/Test(22009): Message.callack()
10-28 11:27:49.328: V/Test(22009): Handler.callack()

好了,这篇文章就到此结束,相信大家对整个Message的流转过程,应该有它的一个清醒的认识。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Android正在使用Handler实现消息分发机制(两)的更多相关文章

  1. Android正在使用Handler实现消息分发机制(零)

    演讲前,AsyncTask文章.我们在最后谈到.AsyncTask它是利用Handler异步消息处理机制,操作结果.使用Message回到主线程,从而执行UI更新线程. 而在我们的日常开发工作,Han ...

  2. Android中利用Handler实现消息的分发机制(三)

    在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...

  3. delphi VCL研究之消息分发机制-delphi高手突破读书笔记

    1.VCL 概貌 先看一下VCL类图的主要分支,如图4.1所示.在图中可以看到,TObject是VCL的祖先类,这也是Object Pascal语言所规定的.但实际上,TObject以及TObject ...

  4. Cocos2d-x 3.0 屏幕触摸及消息分发机制

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  5. Android 消息分发机制

    Android 中针对耗时的操作,放在主线程操作,轻者会造成 UI 卡顿,重则会直接无响应,造成 Force Close.同时在 Android 3.0 以后,禁止在主线程进行网络请求. 针对耗时或者 ...

  6. Android为TV端助力 事件分发机制

    android事件分发机制,给控件设置ontouch监听事件,当ontouch返回true时,他就不会走onTouchEvent方法,要想走onTouchEvent方法只需要返回ontouch返回fa ...

  7. Android面试收集录6 事件分发机制

    转自:秋招面试宝典. 一. 基础认知 1.1 事件分发的对象是谁? 答:事件 当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件). Touch事件相关细节(发 ...

  8. 轻松搞定RabbitMQ(二)——工作队列之消息分发机制

    转自 http://blog.csdn.net/xiaoxian8023/article/details/48681987 上一篇博文中简单介绍了一下RabbitMQ的基础知识,并写了一个经典语言入门 ...

  9. Android正在使用Handler实现信息发布机制(一)

    上一篇文章,我们谈到了电话Handler的sendMessage方法,最后,我们将进入一个电话 sendMessageAtTime方法,例如下列: public boolean sendMessage ...

随机推荐

  1. Benchmark与Profiler---性能调优得力助手

    转载请注明出处:http://blog.csdn.net/gaoyanjie55/article/details/34981077 性能优化.它是一种诊断性能瓶颈,能问题点进行优化的过程.前两天听完s ...

  2. IE浏览器兼容性问题解决方法

    如何用一行代码来解决CSS各种IE各种兼容性问题 一行代码来解决CSS在,IE6,IE7,IE8,IE9,IE10 各种兼容性问题. 在站点前端写代码的过程中,非常多时间IE各个版本号的兼容问题非常难 ...

  3. KMP该算法解释(最长公共子)

    一个:介绍KMP算法之前,首先解释一下BF算法 (1)BF算法(传统的匹配算法,是最简单的算法) BF算法是一种常见的模式匹配算法,BF该算法的思想是目标字符串S模式串的第一个字符P的第一个字符,以匹 ...

  4. Lucene于Directory

    MMapDirectory从继承FSDirectory,抵抗jre至今未能解决Mmap close不回收空间(直到full gc恢复之前,)的bug,lucene使用hack资料恢复(只要sun ja ...

  5. MVC — 第 6 天

    7 天玩转 ASP.NET MVC — 第 6 天   目录 第 1 天 第 2 天 第 3 天 第 4 天 第 5 天 第 6 天 第 7 天 0. 前言 欢迎来到第六天的 MVC 系列学习中.希望 ...

  6. Theano学习笔记(三)——图结构

    图结构(Graph Structures)这是理解Theano该基金会的内部运作. Theano编程的核心是用符号占位符把数学关系表示出来. 图结构的组成部分 如图实现了这段代码: importthe ...

  7. SQL Server的还原

    原文:SQL Server的还原 1.差异备份的还原 不备份结尾日志的情况下还原数据 创建差异备份的放在我们已经在前面一篇博客SQL Server的备份中提到了,这里我们不再赘述,下面我们给出差异备份 ...

  8. JMeter怎么使用代理服务器

    一.JMeter有一个内置的代理服务器,主要用户使用浏览器录制脚本,在左侧的WorkBench中添加HTTP Proxy Server即可, 其中port表示代理服务器段口号, URL Pattern ...

  9. JavaScript之对象序列化详解

    一.什么是对象序列化? 对象序列化是指将对象的状态转换为字符串(来自我这菜鸟的理解,好像有些书上也是这么说的,浅显易懂!): 序列化(Serialization)是将对象的状态信息转换为可以存储或传输 ...

  10. SSIS从理论到实战,再到应用

    原文:SSIS从理论到实战,再到应用 一,是什么(What?) 1.SSIS是Microsoft SQL Server Integration Services的简称,是生成高性能数据集成解决方案(包 ...