Android消息处理机制(Handler、Looper、MessageQueue与Message)
1、Message : 消息
2、MessageQueue : 消息队列
3、Looper:消息循环,用于循环取出消息进行处理(维护消息队列)
4、Handler :Looper在MessageQueue中取出消息后对消息进行处理
我们都知道Android 的入口主程序是 ActivityThread此类的main方法,它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数)。
public final class ActivityThread {
.....................
final Looper mLooper = Looper.myLooper();
.....................
public static void main(String[] args) {
..........................
Looper.prepareMainLooper();
//这里是调用Looper的循环器,不断取出消息并用handler分发
Looper.loop();
.......................
}
}
这就是我们入口主程序了,是不是看到了Looper,这就是对了,android消息机制默认就是主线程,不需要我们手动来启动一个Looper来建立一个主线程来更新UI,而在子线程中,我们则需要手动来开启一个Looper来开启消息循环和停止消息循环。好,我们一步步来,是不是看到了一个全局的mLooper ,通过 Looper.myLooper()的静态方法来获取一个Looper对象,源码查看:
/**Return the Looper object associated with the current
thread. Returns null if the calling thread is not associated with a Looper. */
返回当前线程的Looper对象,如果返回null,则说明当前线程没有相关的Looper对象。
//这个myLoope()方法,主要是获取存储在ThreadLocal的Looper对象
public static Looper myLooper() {
return sThreadLocal.get();
}
再看看 Looper.prepareMainLooper()方法:
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里面,同时把Looper放到ThreadLocal中
下面讲一下Looper类的重要的几个方法:
1、prepare()
在prepare()方法中,判断了一下为不为Null,如果当前的ThreadLocal里面有值,就会抛出异常,ThreadLocal作用是保存当前线程的变量,在这里是保存Looper对象,这说明了该方法不能调用2次,并且一个线程中只有一个Looper对象。并且实例了一个MessageQueue(消息队列)。
public static final void prepare() {
//保证了Looper的唯一性
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//该方法是实例Looper对象,在构造方法中实例了消息队列
sThreadLocal.set(new Looper(true));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
2、loop()方法,稍微有点长……
//这个myLoope()方法,主要是获取存储在ThreadLocal的Looper对象
public static Looper myLooper() {
return sThreadLocal.get();
}
public static void loop() {
//可以看出myLooper该方法就是获取保存在ThreadLocal的Looper对象
//因为可以联想到什么,我们是在prepare()方法实例Looper,并且保存到ThreadLocal中,因为,prepare()方法必须执行于loop()方法之前,否则抛出异常!
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//looper实例中的mQueue(消息队列),在实例Looper中,已经创建了消息队列了,在这里获取消息队列,
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
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);
}
//取出消息的target(就是handler),执行分发消息的处理操作,
//因为dispatchMessage()这个方法是Handler中的,通过Message中的Handler引用来调用该方法来处理消息,在Message中的Hnalder的引用名字就是target,哈哈哈......
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "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.recycleUnchecked();
}
}
好好,既然msg拿到了,也交到了Handler的手中,那么来看看Handler是怎样处理的。
public class 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());
}
}
//获取了当前线程保存的Looper实例,就是上面提到的。
//主要是myLooper这个方法都是获取当前的Looper实例。
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
/**获取了这个Looper实例中保存的MessageQueue(消息队列),上面创建Looper的时候就已经提到了,实例Looper的时候,会构建一个MessageQueue,而在消息队列中获取了Message,又通过了hanler的dispatchMessage()方法,把这个消息发送过去了,下面我们来看看dispatchMessage()这个方法,这样就handler、Looper、MessageQueue就有了关联。*/
mQueue = mLooper.mQueue;//获取上面保存的消息队列
mCallback = callback;//这个就消息的回调,下面有源码
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
//这里把Handler的mQueue指向Looper的mQueue
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
public interface Callback {
public boolean handleMessage(Message msg);
}
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//如果接收到消息中,携带这个callback(线程),就执行这里的逻辑
handleCallback(msg);
} else {
if (mCallback != null) {
//如果实例话Handler时,实现回调接口并传入时就会执行实现逻辑
return;
}
}
//如果上述2个条件都不符合,就执行这里了,比如,what=1
//因为这个就是一个空的方法
handleMessage(msg);
}
}
好了,Handler看了一下,大概明白这个消息机制是怎样的,接下来看看我们通过Handler发送消息的一些方法。
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessageDelayed(
int what, long delayMillis) { //延迟多少时间,常用啦
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
/**延迟执行,一般我们在进入APP过渡界面,就会用到这个方法,或者是操作耗时任务的时候,耗时时间加上系统时间作为发送时间,*/
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);
}
还有一些发送的方法我就不一 一列出了,通过上面的观察,可以发现,最后调用了sendMessageAtTime,在此方法内部有直接获取MessageQueue然后调用了enqueueMessage方法;
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
//把当前Handler的引用也一起传递过去,因为在Looper中通过Hnadler的引用来执行disptchMessage方法
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//发送消息到消息队列
return queue.enqueueMessage(msg, uptimeMillis);
}
//这个是MessageQueue的方法
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException
("Message must have a target.");
}
if (msg.isInUse()) {
(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) {
// 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 (;;) {//如果消息队列有消息(正常情况下,那么该条消息就会被调到最后一条消息)
//这个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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
这些总结是来自Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
这里我从一个handler发送消息---回调消息总结一下。
加上这个图是不是更清晰了,来写下代码,走下流程:
public class MainActivity extends Activity {
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Message message = handler.obtainMessage();
message.what=1;
handler.sendMessage(message);
}
跟踪源码: handler.sendMessage(message);如下:
1、 public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
2、 public final boolean sendMessageDelayed(
Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(
msg, SystemClock.uptimeMillis() + delayMillis);
}
3、 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);
}
4、 private boolean enqueueMessage(
MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
到了这一步,消息已经到了消息队列中了,我们就通过Looper无限循环抽取消息出来,然后通过:
//在一个无限循环中不断取出消息
Message msg = queue.next();
msg.target.dispatchMessage(msg);
再通过这个方法,回调到Hanlder中进行消息的处理!
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//如果接收到消息中,携带这个callback(线程),就执行这里的逻辑
handleCallback(msg);
} else {
if (mCallback != null) {
//如果实例话Handler时,实现回调接口并传入时就会执行实现逻辑
return;
}
}
//如果上述2个条件都不符合,就执行这里了,比如,what=1
//因为这个就是一个空的方法
handleMessage(msg);
}
}