Android 之 Handler ,Looper机制详解
Android 之 Handler ,Looper机制详解
Handler 在日常开发中异步操作时经常使用到,接下来我们就来分析Handler机制,主要分为两大部分:
- 常见用法
- 源码解读
常见用法
一般我们会在Acticity或者其他地方中new一个Handler ,并重写handleMessage的方法,在handleMessage中接受传过来的消息:
private Handler mHandler = getLocalHandler();
private final static int FIRST_MESSAGE = 1;
private final static int SECOND_MESSAGE = 2;
public Handler getLocalHandler() {
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FIRST_MESSAGE:
//doFirstThing();
break;
case SECOND_MESSAGE:
//doSecondThing();
break;
default:
break;
}
}
};
return handler;
}
然后可以在 其他的线程 或者 主线程 发消息给Handler,比如异步网络加载完数据之后:
private void sendMessageToFirst() {
Message msg = new Message();
msg.obj = null;
//可用 msg.what 来区别并执行不同的事项
msg.what = FIRST_MESSAGE;
mHandler.sendEmptyMessage(FIRST_MESSAGE);
}
在 异步线程 或 主线程 我们也可以利用Handler来做延时处理操作:
private void sendMessageDelayed() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
doSecondThing();
}
},2333);
}
上诉就是我们比较常规的用法。
源码解读篇
接下来我们来分析下Handler,Looper机制的java源码
Handler(初始化):
首先看下new时Handler的构造器,代码如下:
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
//...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException("");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到,new时初始化 mLooper (Looper) ,mQueue (MessageQueue) ,mCallback (Callback) ,mAsynchronous (Boolean) 这四个对象。
下面我们逐一来分析他们:
Callback :
先说Callback,Callback是Handler类中的接口,其中的handleMessage与我们上述Handler重写的handleMessage是一样的方法名:
public interface Callback {
public boolean handleMessage(Message msg);
}
我们直接看他调用的地方,它在dispatchMessage方法中被使用,dispatchMessage(Message msg) 是处理消息的分发的方法,而方法中的 handleMessage(msg) ,它是我们执行 handler中 sendMessage,post(Runnable)等方法的执行语句
// dispatchMessage方法中被使用,dispatchMessage(Message msg)
// 是处理消息的分发的方法
public void dispatchMessage(Message msg) {
//..
// 这个为callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//执行handler中 sendMessage,post等方法的分发执行语句
handleMessage(msg);
}
再看下callback调用的地方,可看到当 mCallback != null 且 mCallback.handleMessage(msg) 为 true 的时候 return 方法不继续往下走。不然执行handleMessage(msg),这说明我们在 handler 事件执行前多执行一些操作 或者 截断handler事件的执行,所以可以使用下述的初始化Handler构造器,不过很少使用到这个。
//Handler.class
public Handler(Callback callback) {
this(callback, false);
}
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//可以在事件发送前自定义处理
// doSomeThing();
return false;
}
});
Looper:
接下来我们看下 mLooper 参数,它被赋值了 Looper.myLooper(),我们进Looper进去看,相关代码贴下去:
static final ThreadLocal<Looper> sThreadLocal
= new ThreadLocal<Looper>();
public static Looper myLooper() {
return sThreadLocal.get();
}
可以看到是从 sThreadLocal 获取一个Looper,使得且一个线程只有一个Looper,大家可以去网上搜索ThreadLocal的知识理解为什么线程只有一个Looper。在 get 之前肯定需初始化,我们找到初始化的地方,代码如下:
private static Looper sMainLooper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("");
}
sMainLooper = myLooper();
}
}
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在代码中,我们可以看到新建了一个MessageQueue,我们进去看下:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException(
"Main thread not allowed to quit.");
}
// ...
}
其中quitAllowed代表这个消息队列是否可以停止,上诉可以看到赋值为false时,调用quit()方法会报异常, 而mPtr是被底层c++使用,这个我们先不理。此时初始化已经分析完毕。
Handler机制(启动):
在我们程序启动时,系统会调用 prepareMainLooper() 方法,并初始化主线程的 Looper ,使主线程有可以使用的 Looper(),其中prepareMainLooper() 中 prepare(false) 会使Looper运行起来且不允许MessageQueue消息队列中断,这也可以理解不然在主UI中中断了可就不好了,代码如下:
// ActivityThread.class 主程序的入口
public static void main(String[] args) {
// ..
Looper.prepareMainLooper();
// ..
Looper.loop();
// ..
}
在上面可以看到在主程序开始时就就调用了prepareMainLooper()并使Looper loop()了起来,我们看下loop()方法,代码如下 :
public static void loop() {
final Looper me = myLooper();
// ...
final MessageQueue queue = me.mQueue;
// ...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
// ...
try {
msg.target.dispatchMessage(msg);
} finally {
// ...
}
// ...
msg.recycleUnchecked();
}
}
可以看到方法中,获取当前MessageQueue对象,并开启了死循环,当queue.next()消息队列没有消息就return继续等待,有消息的话就往下执行 msg.target.dispatchMessage(msg) 语句。我们去先下queue.next()中的内容,代码如下:
// MessageQueue.class
Message next() {
// 当loop被停止或者弃用 ptr 为0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
//...
// 下一次消息触发时间
int nextPollTimeoutMillis = 0;
for (;;) {
//...
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 如果同步时执行 且 msg.target == null执行
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;
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
}
//...
}
}
我们可以看到通过next()方法,我们可以获取消息继而执行,接着target是什么,代码如下:
// Message.class
Handler target;
可以看到 target 是个Handler对象,之前有稍微讲下Handler的dispatchMessage()方法,让我们再看一遍详细代码:
// Handler.class
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
}
可以看到当传下来的消息msg中的callback不为空的时候,直接执行run()方法,不然就判断mCallback 是否为空且mCallback.handleMessage(msg)是否为true,不然就执行我们重写的handleMessage()方法。
那么target又是哪里赋值的呢,我们先看Message的构造器,代码如下:
// Message.class
public Message() {
}
发现并没有赋值target的值,我们回想一般在新建Message消息后我们会发送出来,我们去那个方法看下:
// Handler.class
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) {
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue,
Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
到最后我们可以发现target = this为我们当前的Handler,最后我们看下enqueueMessage方法,代码如下:
// MessageQueue.class
boolean enqueueMessage(Message msg, long when) {
//...
synchronized (this) {
if (mQuitting) {
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// mMessages可以理解为上一次Message
// 当mMessages不为空,或者启动时间为0的,或者启动时间小于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;
}
上述代码就是Message插入队列的代码。
总结:
Handler机制其实在Android机制中算比较好理解的,我们可以看到主要涉及的类有Handler,Looper,MessageQueue和Message。
在主线程中,
Handler:负责对外,比如消息的添加,移除等功能,
Looper:个人理解作为一个载体,承载着消息队列的启动,获取及销毁消息,使Handler不必对MessageQueue进行管理,专注处理对外事件的处理
MessageQueue:对消息的循环移除,及对C++代码的通信。其中涉及到部分的jni代码本篇暂时还没解析,有兴趣的同学可以自行了解或谷歌。
这也是本人的第一篇博客,如果有什么写的错误或者不足的,请大家留言帮忙纠错!0-0
推荐阅读
-
详解Android中Handler的使用方法
-
详解Android中Handler的内部实现原理
-
Android Handler移除Message详解及实例代码
-
android线程消息机制之Handler详解
-
详解Android之解析XML文件三种方式(DOM,PULL,SAX)
-
Android AOP之注解处理解释器详解(二)
-
Android开发之MediaPlayer基本使用方法详解
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
Android开发之图形图像与动画(五)LayoutAnimationController详解
-
Android设计模式之单例模式详解