Android的消息处理有三个核心类:Looper, Handler和 Message。其实还有一个MessageQueue,它是Looper的一个成员引用变量。
Looper的字面意思是“循环”,设计成用来使一个普通线程变成Looper线程。在程序开发中特别是GUI开发中,经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。
使用Looper类创建Looper线程很简单:
public class LooperThread extends Thread {
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
// ...其他处理,如实例化handler
// 开始循环处理消息队列
Looper.loop();
}
}
1)Looper.prepare()
通过上图可以看到,线程中有一个Looper对象,它的内部维护了一个消息队列MessageQueue。注意,一个Thread只能有一个Looper对象,
public class Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
// 。。。其他属性
// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
// 我们调用该方法会在调用线程的TLS中创建Looper对象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// 其他方法
}
2)Looper.loop()
调用loop方法后,Looper线程就开始真正工作了,它不断从MessageQueue中取出队头的消息执行。其源码分析如下:
public static final void loop() {
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ
// 这两行没看懂= = 不过不影响理解
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
// 日志。。。
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
// 下面没看懂,同样不影响理解
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 回收message资源
msg.recycle();
}
}
}
除了prepare()和loop()方法,Looper类还提供了一些有用的方法,比如
Looper.myLooper()得到当前线程looper对象:
public static final Looper myLooper() {
// 在任意线程调用Looper.myLooper()返回的都是那个线程的looper
return (Looper)sThreadLocal.get();
}
getThread()得到looper对象所属线程:
public Thread getThread() {
return mThread;
}
quit()方法结束looper循环:
public void quit() {
// 创建一个空的message,它的target为NULL,表示结束循环消息
Message msg = Message.obtain();
// 发出消息
mQueue.enqueueMessage(msg, 0);
}
Looper总结如下:
1. 每个线程有且最多只能有一个Looper对象,它是一个ThreadLocal<Looper>
2. Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行
3. Looper使一个线程变成Looper线程。
Handler扮演了向MessageQueue上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MessageQueue它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。Handler创建时会关联一个Looper,默认的构造方法将关联当前线程的Looper,当然也可以自己设置的。默认的构造方法:
public class handler {
final MessageQueue mQueue; // 关联的MQ
final Looper mLooper; // 关联的looper
final Callback mCallback;
// 其他属性
public Handler() {
// 没看懂,直接略过,,,
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 默认将关联当前线程的looper
mLooper = Looper.myLooper();
// looper不能为空,即该默认的构造方法只能在looper线程中使用
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 重要!!!直接把关联looper的MessageQueue作为自己的MessageQueue,因此它的消息将发送到关联looper的MessageQueue上
mQueue = mLooper.mQueue;
mCallback = null;
}
// 其他方法
}
下面就可以为之前的LooperThread类加入Handler:
public class LooperThread extends Thread {
private Handler handler1;
private Handler handler2;
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
// 实例化两个handler
handler1 = new Handler();
handler2 = new Handler();
// 开始循环处理消息队列
Looper.loop();
}
}
加入handler后的效果如下图:
一个线程可以有多个Handler,但是只能有一个Looper!
Handler发送消息
创建Handler后可以使用 post(Runnable)
, postAtTime(Runnable, long)
, postDelayed(Runnable, long)
, sendEmptyMessage(int)
, sendMessage(Message)
, sendMessageAtTime(Message, long)
和 sendMessageDelayed(Message, long)
这些方法向MessageQueue上发送消息。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,其实发出的Runnable对象最后也被封装成message对象了,见源码:
// 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行
public final boolean post(Runnable r)
{
// 注意getPostMessage(r)将runnable封装成message
return sendMessageDelayed(getPostMessage(r), 0);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain(); //得到空的message
m.callback = r; //将runnable设为message的callback,
return m;
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this; // message的target必须设为该handler!
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
通过Handler发出的message的特点:
1. message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码
msg.target.dispatchMessage(msg);
2. post发出的message,其callback为Runnable对象
Handler处理消息
消息的处理是通过核心方法dispatchMessage(Message msg)与handleMessage(Message msg)方法完成的,见源码
// 处理消息,该方法由looper调用
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果message设置了callback,即runnable消息,处理callback!
handleCallback(msg);
} else {
// 如果handler本身设置了callback,则执行callback
if (mCallback != null) {
/* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果message没有callback,则调用handler的钩子方法handleMessage
handleMessage(msg);
}
}
// 处理runnable消息
private final void handleCallback(Message message) {
message.callback.run(); //直接调用run方法!
}
// 由子类实现的钩子方法
public void handleMessage(Message msg) {
}
可以看到,除了handleMessage(Message msg)和Runnable对象的run方法由开发者实现外(实现具体逻辑),handler的内部工作机制对开发者是透明的。
Handler的用处
Handler拥有下面两个重要的特点:
1.handler可以在任意线程发送消息,这些消息会被添加到关联的MessageQueue上。
2.handler是在它关联的looper线程中处理消息的。
Android的主线程也是一个Looper线程,在其中创建的handler默认将关联主线程MessageQueue。因此,利用handler的常用场景就是在activity中创建handler并将其引用传递给你的线程,你的线程执行完任务后使用handler发送消息通知Activity更新UI。(过程如图)
下面给出sample代码,仅供参考:
public class TestDriverActivity extends Activity {
private TextView textview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textview = (TextView) findViewById(R.id.textview);
// 创建并启动工作线程
Thread workerThread = new Thread(new SampleTask(new MyHandler()));
workerThread.start();
}
public void appendText(String msg) {
textview.setText(textview.getText() + "\n" + msg);
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
String result = msg.getData().getString("message");
// 更新UI
appendText(result);
}
}
}
public class SampleTask implements Runnable {
private static final String TAG = SampleTask.class.getSimpleName();
Handler handler;
public SampleTask(Handler handler) {
super();
this.handler = handler;
}
@Override
public void run() {
try { // 模拟执行某项任务,下载等
Thread.sleep(5000);
// 任务完成后通知activity更新UI
Message msg = prepareMessage("task completed!");
// message将被添加到主线程的MQ中
handler.sendMessage(msg);
} catch (InterruptedException e) {
Log.d(TAG, "interrupted!");
}
}
private Message prepareMessage(String str) {
Message result = handler.obtainMessage();
Bundle data = new Bundle();
data.putString("message", str);
result.setData(data);
return result;
}
}
当然,handler能做的远远不仅如此,由于它能post Runnable对象,它还能与Looper配合实现经典的Pipeline Thread(流水线线程)模式。
整个消息处理机制中,message封装了任务携带的信息和处理该任务的handler。message的用法比较简单,有几点需要注意:
1. 尽管Message有public的默认构造方法,但是应该通过Message.obtain()来从消息池中获得空消息对象,以节省资源。
2. 如果你的message只需要携带简单的int信息,请优先使用Message.arg1和Message.arg2来传递信息,这比用Bundle更省内存;
3. 擅用message.what来标识信息,以便用不同方式处理message。
=============================================================================
下面是转载的一篇介绍消息机制的整个流程:
每一个handler其实都绑定了一个线程(Thread)和消息队列(MessageQueue),消息队列中存放的是一堆待处理的消息,Looper通过一个loop方法不断从消息队列中获取到消息(Message)(先进先出的方式),执行消息队列的出队方法,然后该消息会通过自身绑定target(其实是一个handler对象),分发处理携带的消息(dispatchMessage)。消息处理完成之后,该消息会被回收(recycle),回到消息池中。而handler的sendMessage方法其实会调用消息队列的入队方法(enqueueMessage),将包装好的消息加到消息队列中,再次循环。这其实就是android下的消息机制。本文将试图从源码的角度分析这一流程。
首先介绍Handler,Looper,MessageQueue,Message四个概念:
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
-------------------------------------
注:一个线程默认是没有消息队列的,如果我们要使用handler,必须指定Looper,Looper内部会创建MessageQueue。其中比较特殊的是UI线程提供了默认的Looper,我们不需要为其指定Looper。如果是其他线程,我们必须显式调用Looper.prepare和Looper.loop方法创建Looper并使其运转起来。
- class LooperThread extends Thread {
- public Handler mHandler;
- public void run() {
- Looper.prepare();
- mHandler = new Handler() {
- public void handleMessage(Message msg) {
-
- }
- };
- Looper.loop();
- }
- }
----------------------
下面我们将从Handler调用post或者sendMessage方法开始,跟踪源码进行分析,从而了解整个消息机制的运作过程。
我们在调用sendMessage方法时,需要提供一个Message对象,Message对象用于封装一个消息,我们通过查看源码观察下该类的成员变量:
- public final class Message implements Parcelable {
- public int what;
- public int arg1;
- public int arg2;
- public Object obj;
-
- long when;
- Bundle data;
- Handler target;
- Runnable callback;
-
- Message next;
- private static final Object sPoolSync = new Object();
- private static Message sPool;
- private static int sPoolSize = 0;
- private static final int MAX_POOL_SIZE = 50;
- ... ...
四个公有变量相信大家都不陌生,这里就不再介绍了。我们看到Message还有一些成员变量,比如说target,这是个Handler对象,target可以通过set方法或者obtainMessage等方式设置,一旦设置了Target,这个message就被绑定到一个具体的handler上了,然后message内部即可调用sendToTarget方法将message交给绑定的Handler进行处理,内部也调用的是sendMessage:- public void sendToTarget() {
- target.sendMessage(this);
- }
callback对象是Runnable类型的,这个也比较好理解,因为我们的handler除了可以处理message之外,还可以通过Post方式将Runnable加入队列,进行处理。这个执行流程我们放在后面介绍。
我们还看到了一个Message类型的next,这个成员变量持有了下一个Message的引用,众多Message就是通过这种方式形成一个链表,也就是所谓的消息池,我们看到消息池默认的容量为0(sPoolSize),池的最大容量为50。Message的obtain及其重载形式每次调用都会从池中取出一个Message,如果不存在就new一个出来。
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
recycle方法又会将用完的Message回收:- public void recycle() {
- clearForRecycle();
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {
- next = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
现在假设我们的消息已经封装好了,下一步必然就是发送消息了。通过调用Handler的sendMessage方法可以发送一条消息。
- public final boolean sendMessage(Message msg)
- {
- return sendMessageDelayed(msg, 0);
- }
sendMessage方法调用了sendMessageDelayed方法,延时设为0,继续跟源码:- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
先是判断延时参数的合法性,然后调用了sendMessageAtTime方法,果断跟进去看看:- 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);
- }
跟到这一步,我们发现了一个没见过的变量,mQueue,查看该变量定义:- ......
- final MessageQueue mQueue;
- final Looper mLooper;
- final Callback mCallback;
- ......
原来mQueue是一个消息队列,那么消息队列是怎么初始化的呢?我们找到Handler的一个构造器:- public Handler(Callback callback, boolean async) {
- ... ...
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
原来mQueue是Looper的成员变量,这个构造器通过Looper.myLooper方法返回了一个与当前线程绑定的Looper对象,进而获取到与Looper绑定的MessageQueue。这是Looper的构造器:- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mRun = true;
- mThread = Thread.currentThread();
- }
既然我们知道了mQueue的来历,那么我们继续随着上面的思路跟进吧!刚才我们通过跟踪sendMessage源码发现内部最终调用了sendMessageAtTime方法,而这个方法又调用了enqueueMessage方法,从名字上能看出,该方法是将消息出队的方法,等等。。消息出队不应该是消息队列的方法么?怎么Handler也有?别急,我们查看enqueueMessage方法源码:- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
这下原因显而易见了,handler的入队方法其实调用的是消息队列的入队方法。
下面我们来到MessageQueue源码,查找到enqueueMessage方法:
- final boolean enqueueMessage(Message msg, long when) {
- if (msg.isInUse()) {
- throw new AndroidRuntimeException(msg + " This message is already in use.");
- }
- if (msg.target == null) {
- throw new AndroidRuntimeException("Message must have a target.");
- }
- boolean needWake;
- synchronized (this) {
- if (mQuiting) {
- RuntimeException e = new RuntimeException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- }
- msg.when = when;
- Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {
-
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;
- } else {
- 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;
- prev.next = msg;
- }
- }
- if (needWake) {
- nativeWake(mPtr);
- }
- return true;
- }
跟到这里终于明白了,这个MessageQueue是通过mMessages变量来记录当前待处理的消息,通过Mesage的发送的时间进行排序(调用msg.next)。
到这里整个入队操作就分析完了,通过这一系列的操作,handler将消息发送给了消息队列。到这里消息只是不断被加到消息队列中,我们并没有取出消息。那么Handler的handMessage方法又是怎么被调用的呢??带着这个疑问,我们来研究下Looper,消息泵,既然是泵,之所以叫泵,是因为它可以从消息队列中取出消息!之前说过,要在线程中使用Handler,必须调用Looper的prepare方法创建Looper对象,然后调用loop方法让消息队列运作起来。那么,这个loop方法是关键,我们查看该方法源码:
- public static void loop() {
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- final MessageQueue queue = me.mQueue;
- Binder.clearCallingIdentity();
- ... ...
- for (;;) {
- Message msg = queue.next();
- if (msg == null) {
- return;
- }
- ... ...
- msg.target.dispatchMessage(msg);
- ... ...
- msg.recycle();
- }
- }
这个方法首先获取到消息队列的一个引用,然后在一个死循环中反复调用消息队列的出队方法(next)获取到下一个待处理的消息的引用,然后调用该消息所绑定的handler的dispatchMessage方法分发消息,最后将该消息回收。我们跟踪Handler的dispatchMessage方法:- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
既然是分发消息的方法,那必然会根据消息的类型做出不同的处理,这个方法正是根据Message对象是否携带了callback,如果携带了callback那就执行handleCallback方法,callback之前分析Message类的时候已经知道是一个Runnable的对象了。下面我们看看handleCallback是什么实现的:- private static void handleCallback(Message message) {
- message.callback.run();
- }
一目了然!直接调用callback的run方法。之前我们用post方法发送消息时携带的Runnable对象在Handle内部被转化为一个Message:- private static Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;
- return m;
- }
post方法中的Runnable对象被转成Message之后也会进入消息队列,最终被Looper抽取出来,让handler进行处理。
普通的sendMessage方法是不携带callback的,这时便进入dispatchMessage方法的else分支,进入else分支后,首先判断handler是否有一个CallBack的回调函数,如果有,直接调用回调函数的handMessage方法,这个CallBack是一个接口,它的好处是我们不用在继承Handler重写handleMessage方法了,CallBack接口定义:
- public interface Callback {
- public boolean handleMessage(Message msg);
- }
如果没有实现回调接口,那么便调用Handle的handMessage方法处理消息。
-------------------------------------------
通过上面的一番分析,我们终于明白了android下的消息机制的运作原理了,为了更形象的说明整个流程,这里贴一张示意图:
==================================================================================================================
下面源码分析篇也是转载:
Android中消息传递模块差不多看了好几次,虽然每次看的方式都差不多但是还是发觉的到每次看了之后,理解的更清晰一点。
关于这个模块的文章数不胜数,但是最重要的还是自己动手理解一遍更好。
会牵扯到的几个类: Handler.java , Looper.java , MessageQueue.java , Message.java
源代码路径:
xxx/frameworks/base/core/java/android/os 看的过程中你会发现高版本和低版本系统代码有些地方比较大的差距。从中我们可以分析为什么要做这样的修改,这样的修改的优点。
先看看在Looper类的注释中的一段代码。
- * <p>This is a typical example of the implementation of a Looper thread,
- * using the separation of {@link #prepare} and {@link #loop} to create an
- * initial Handler to communicate with the Looper.
- *
- * <pre>
- * class LooperThread extends Thread {
- * public Handler mHandler;
- *
- * public void run() {
- * Looper.prepare();
- *
- * mHandler = new Handler() {
- * public void handleMessage(Message msg) {
- *
- * }
- * };
- *
- * Looper.loop();
- * }
- * }</pre>
- */
Looper.java
这里Looper.prepare() ; 和 Looper.loop() ;这两个方法做了什么?
-
-
-
-
-
-
- public static void prepare() {
- prepare(true);
- }
-
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
-
- sThreadLocal.set(new Looper(quitAllowed));
- }
当我们手动调用Looper.prepare()方法的时候,内部调用prepare(boolean quitAllowd)方法,参数quitAllowd表示是否允许退出。
Android中刷新UI都在main线程中完成的,因此prepare(false)的时候是在启动main线程的时候会用到。我们可以看到Looper中另外一个方法:
-
-
-
-
-
-
-
-
-
- public static void prepareMainLooper() {
- prepare(false);
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
Looper.prepare()方法中,完成了Looper的创建并将起存储至ThreadLocal变量中。
从上面代码中可以看到:
sThreadLocal.set(new Looper(quitAllowed));
因此下面我们跟踪一下Looper的构造方法、
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
-
- mThread = Thread.currentThread();
- }
构造方法中看到创建了MessageQueue和得到当前线程的Thread对象。这里的MessageQueue是后面消息循环以及消息的传递重要的部分。因此,从这里我们可以看出,Looper中持有:MessageQueue,currentThread,ThreadLocal。
接下来看下,Looper.loop()方法。注:方法中部分打印Log相关的代码此处已经删除。
Android Source Code 4.4
-
-
-
-
- public static void loop() {
-
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
-
- final MessageQueue queue = me.mQueue;
-
-
-
- Binder.clearCallingIdentity();
-
- for (;;) {
-
- Message msg = queue.next();
- if (msg == null) {
-
- return;
- }
-
-
-
- msg.target.dispatchMessage(msg);
-
-
- msg.recycle();
- }
- }
对比Android Source Code 2.3 -
-
-
-
- public static final void loop() {
- Looper me = myLooper();
- MessageQueue queue = me.mQueue;
-
-
-
- Binder.clearCallingIdentity();
-
- while (true) {
- Message msg = queue.next();
-
-
-
- if (msg != null) {
- if (msg.target == null) {
-
- return;
- }
-
- msg.recycle();
- }
- }
- }
从上面的对比可以看出4.4的代码明显比2.3的代码变化。1.while(true){...}循环修改为for(,,){...} 貌似这里没啥区别
2.Looper me = myLooper();获取到当前looper,4.4加了非空判断。因为在调用了Looper.prepare()后才会有Looper产生。可以看上面的分析。
3.去掉了message中target判断空的if语句。
分析为何这里去掉。
先看当我们调用Handler的handler.obtainMessage() ;
------->in Handler.java
-
-
-
-
-
- public final Message obtainMessage()
- {
- return Message.obtain(this);
- }
此时Handler会去调用Message的obtain方法,该方法将this作为参数传递进去,也就是将当前的Handler对象引用传递进去。
----->in Message.java
-
-
-
-
-
-
-
-
-
-
-
- public static Message obtain(Handler h, int what,
- int arg1, int arg2, Object obj) {
- Message m = obtain();
- m.target = h;
- m.what = what;
- m.arg1 = arg1;
- m.arg2 = arg2;
- m.obj = obj;
-
- return m;
- }
而且再看看当msg被添加到队列的时候调用的方法
boolean enqueueMessage(Message msg,long when)其中首先就是判断将被添加的target是否为null,否则跑出nullPointerException。
- boolean enqueueMessage(Message msg, long when) {
- if (msg.target == null) {
- throw new IllegalArgumentException("Message must have a target.");
- } ......
因此msg.target不可能为空,也就没有判断的必要。
4.将可能的情况都先放到前面过滤,减少了if语句的嵌套。是代码更加清晰明了。
刚好手上也有5.0的代码,干脆也贴上来看下。
-
-
-
-
- public static void loop() {
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- final MessageQueue queue = me.mQueue;
-
-
-
- Binder.clearCallingIdentity();
- for (;;) {
- Message msg = queue.next();
- if (msg == null) {
-
- return;
- }
-
- msg.target.dispatchMessage(msg);
-
- msg.recycleUnchecked();
- }
- }
对比可以发现5.0的和4.4的差不多只是msg的回收方法变了。编程recycleUnchecked()。因此这里需要对比4.4的Message和5.0的Message。这里简单看下不同点。
-------->5.0 Message.java 添加了当前msg是否正在使用的校验。当然,这里添加了,说明很多地方也会相应的增加判断校验,差别就出来了。
-
-
-
-
-
-
-
-
- public void recycle() {
- if (isInUse()) {
- if (gCheckRecycle) {
- throw new IllegalStateException("This message cannot be recycled because it "
- + "is still in use.");
- }
- return;
- }
- recycleUnchecked();
- }
Handler.java
平时我们在代码中是直接创建Handler的派生类或者创建匿名内部类。类似于这样
- private static class MyHandler extends Handler{
-
- @Override
- public void handleMessage(Message msg) {
-
- super.handleMessage(msg);
- }
- }
或者- Handler mHandler = new Handler(){
-
- @Override
- public void handleMessage(Message msg) {
-
- super.handleMessage(msg);
- }
-
- } ;
————————————————————————————————————————————————————————
这里我们最先看看Handler的创建。构造方法中最终会调用到这个:
- public Handler(Callback callback, boolean async) {
- if (FIND_POTENTIAL_LEAKS) {
-
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
-
-
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
-
-
- mQueue = mLooper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
上面代码中,第一个if语句判断当前Handler是否为static,警示Handler最好为static这样可以防止内存泄露,至于为什么,这里就不讲了。可以看到,mLooper = Looper.myLooper();mQueue = mLooper.mQueue;与thread绑定的Looper对象的东西也分享给了Handler,这样MessageQueue,Message,Handler,Looper就连接起来了。Handler中移除msg,msg入队列等都是在Looper的MessageQueue中操作。
我们发送消息:- Message msg = handler.obtainMessage() ;
- msg.what = 1 ;
- msg.obj = "Hello World" ;
- handler.sendMessage(msg) ;
这样就能在hangleMessage(Message msg)方法中接收到消息了。该消息是如何传递的?先看sendMessage(msg)做了什么。
---------->code in 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);
- }
先看下这个注释,返回true则表示msg成功添加进了queue中,false则表示该msg正在被执行或者looper异常退出了。
- * @return Returns true if the message was successfully placed in to the
- * message queue. Returns false on failure, usually because the
- * looper processing the message queue is exiting. Note that a
- * result of true does not mean the message will be processed -- if
- * the looper is quit before the delivery time of the message
- * occurs then the message will be dropped.
- */
- ublic boolean sendMessageAtTime(Message msg, long uptimeMillis)
------>最后- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
-
- return queue.enqueueMessage(msg, uptimeMillis);
- }
有个使用,我们将优先级搞得消息添加到队列头部- public final boolean sendMessageAtFrontOfQueue(Message msg) {
- 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, 0);
- }
注意它直接调用了enqueueMessage,第三个参数是0。因此我们从其他方法调用可以看到这里的第三个参数应该是和消息的先后有关系。——————————————————————————————————————
这里先跟一下,sendMessageAtFrontOfQueue方法的流程。
- boolean enqueueMessage(Message msg, long when) {
- if (msg.target == null) {
- throw new IllegalArgumentException("Message must have a target.");
- }
- if (msg.isInUse()) {
- throw new IllegalStateException(msg + " This message is already in use.");
- }
-
- synchronized (this) {
- if (mQuitting) {
- IllegalStateException e = new IllegalStateException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- msg.recycle();
- return false;
- }
-
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
-
- if (p == null || when == 0 || when < p.when) {
-
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;
- } else {
-
-
-
- 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;
- prev.next = msg;
- }
-
-
- if (needWake) {
- nativeWake(mPtr);
- }
- }
- return true;
- }
链表。。。。呵呵呵。。。。。看的有点绕。——————————————————————————————————————
回到Looper.loop()方法中,可以看到这一句,msg.target.dispatchMessage(msg) ,将msg给msg.target去处理,而这个target就是发送消息的Handler自身
-
-
-
-
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
这里的几个判断我就不讲了。
MessageQueue.java
上面Looper.loop()方法中queue.next()
- Message next() {
- int pendingIdleHandlerCount = -1;
- int nextPollTimeoutMillis = 0;
- for (;;) {
- if (nextPollTimeoutMillis != 0) {
- Binder.flushPendingCommands();
- }
-
-
-
- nativePollOnce(mPtr, nextPollTimeoutMillis);
-
- synchronized (this) {
-
- final long now = SystemClock.uptimeMillis();
- Message prevMsg = null;
- Message msg = mMessages;
- if (msg != null && msg.target == null) {
-
- do {
- prevMsg = msg;
- msg = msg.next;
- } while (msg != null && !msg.isAsynchronous());
- }
- if (msg != null) {
- if (now < msg.when) {
-
- nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
- } else {
-
- 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 {
-
- nextPollTimeoutMillis = -1;
- }
-
-
- if (mQuitting) {
- dispose();
- return null;
- }
-
-
-
-
- if (pendingIdleHandlerCount < 0
- && (mMessages == null || now < mMessages.when)) {
- pendingIdleHandlerCount = mIdleHandlers.size();
- }
- if (pendingIdleHandlerCount <= 0) {
-
- mBlocked = true;
- continue;
- }
-
- if (mPendingIdleHandlers == null) {
- mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
- }
- mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
- }
-
-
-
- for (int i = 0; i < pendingIdleHandlerCount; i++) {
- final IdleHandler idler = mPendingIdleHandlers[i];
- mPendingIdleHandlers[i] = null;
-
- boolean keep = false;
- try {
- keep = idler.queueIdle();
- } catch (Throwable t) {
- Log.wtf("MessageQueue", "IdleHandler threw exception", t);
- }
-
- if (!keep) {
- synchronized (this) {
- mIdleHandlers.remove(idler);
- }
- }
- }
-
-
- pendingIdleHandlerCount = 0;
-
-
-
- nextPollTimeoutMillis = 0;
- }
- }
这个方法我没理顺。估计理顺的话要牵扯到其他部分的逻辑。这里就有个疑问,我用Handler发送了好几个msg,而且时间不一样,MessageQueue是如何做的处理呢? 应该和上面的next()方法有很大关系。这里就不研究了,先就到这里。
另外,Message.java实现了Parceable接口。比较java中的serializable接口。
- public final class Message implements Parcelable
这里看看实现Parceable接口需要做的工作吧。
- public static final Parcelable.Creator<Message> CREATOR
- = new Parcelable.Creator<Message>() {
- public Message createFromParcel(Parcel source) {
- Message msg = Message.obtain();
- msg.readFromParcel(source);
- return msg;
- }
-
- public Message[] newArray(int size) {
- return new Message[size];
- }
- };
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- if (callback != null) {
- throw new RuntimeException(
- "Can't marshal callbacks across processes.");
- }
- dest.writeInt(what);
- dest.writeInt(arg1);
- dest.writeInt(arg2);
- if (obj != null) {
- try {
- Parcelable p = (Parcelable)obj;
- dest.writeInt(1);
- dest.writeParcelable(p, flags);
- } catch (ClassCastException e) {
- throw new RuntimeException(
- "Can't marshal non-Parcelable objects across processes.");
- }
- } else {
- dest.writeInt(0);
- }
- dest.writeLong(when);
- dest.writeBundle(data);
- Messenger.writeMessengerOrNullToParcel(replyTo, dest);
- }
-
- private final void readFromParcel(Parcel source) {
- what = source.readInt();
- arg1 = source.readInt();
- arg2 = source.readInt();
- if (source.readInt() != 0) {
- obj = source.readParcelable(getClass().getClassLoader());
- }
- when = source.readLong();
- data = source.readBundle();
- replyTo = Messenger.readMessengerOrNullFromParcel(source);
- }
- Andrid中的Looper,Handler,Message研究
- Handler Looper Message源码研究
- Handler Looper Message源码研究
- Aandroid 中的Handler、message、Looper
- Android中的Looper , Handler , Message
- Android中的Handler、Looper、Message等
- Android中的Looper类&Handler &Message
- Android中的Handler,Looper,Message机制
- 详解Android中的Looper,Handler和Message
- Android中的Handler,Looper,Message机制
- android中的多线程,handler,message,looper,messagequeue
- Android中的Looper,Handler,Message和MessageQueue
- Android中的Handler、Looper、Message简要分析
- 深入浅出Android中的Handler,Message,MessageQueue,Looper。
- Android处理程序:Handler Looper Message源码研究
- Android处理程序:Handler Looper Message源码研究
- Looper,Handler,Message,MessageQueue
- Message,MessageQueue,Looper,Handler
- c++推荐看的一些经典书籍
- [oracle]共享服务器模式下processes参数是否限制连接数
- linux 无密码登录配置里的注意事项
- Bugzilla安装和编辑所遇到的问题
- android_asset URI详细使用方法
- Andrid中的Looper,Handler,Message研究
- oracle中bulk collect into用法
- 机房收费系统总结
- cocos2d-x 2.0通过CCAnimation实例获取CCSpriteFrame
- WdatePicker IE下报错: SCRIPT70: 没有权限 ——解决办法
- 浅谈SQL之主键、外键约束
- GROUPING函数的使用
- Android 高仿三星日历
- 如何将安卓的textview中文本链接到网页