闲来无事,所以一观Android Handler源码
首先我们要构建一个Handler,在这里我们就使用最简单的 new Handler()来构建。
我们调用了new Handler()以后。handler会调用下面的代码
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
//...省略部分无关代码
mLooper = Looper.myLooper(); //构建Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //从Looper中取出消息队列
mCallback = callback;
mAsynchronous = async;
}
观察上面代码。我们可以看到,其中最核心的代码就是构建Looper的代码。而我们在子线程中构建Handler报错
“Can’t create handler inside thread that has not called Looper.prepare()”);
其中出问题的地方我们观察上面代码就是“ Looper.myLooper();” ,所以我们接下来仔细观察一下Looper的构建。
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
从上面我们可以看到" Looper.myLooper();" ,最终是从sThreadLocal中取出了一个Looper对象,而sThreadLocal是一个ThreadLocal对象。如果不了解ThreadLocal的话,可以看下这篇文章
简单来说,我们可以把它理解为一个只有当前线程能访问的变量池。那么既然是变量池,而我们上面的方法是取值,所以我们就必须找到存值的地方。
而我们找遍Looper类,也只有一个地方调用了存值的方法
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //保证每个线程只有一个Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
看到这里你是不是有点明白了,为啥每次在子线程中创建Handler报错 “Can’t create handler inside thread that has not called Looper.prepare()”); ,我们只需要在Handler创建前调用一下Looper.prepare()就可以解决这个错误了。
那为啥我们在子线程中新建Handler必须要手动调用Looper.prepare(),而在主线程中,则不需要调用了。聪明的你一定想到了,在主线程中一定有一位“雷锋”帮我们做了这件事。那么接下来我们就是找出这位“雷锋”。
其中上面这两个prepare方法在系统多处都有调用,但是我们找到一个最像帮我们在activity干活的方法。
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
在这里,我特意把方法的说明也贴上来了。最后一句话,意思就是,我们永远不需要自己手动去调用它。那么接下来,我们看下程序哪里自动的调用了它。
我们使用一下As的自动跳转功能,发现一共有两个地方调用了,一个是SystemServer,一个是ActivityThread。根据名字,我们应该找的是ActivityThread。
public static void main(String[] args) {
//...省略前面无关代码
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
//在attach方法中会完成Application对象的初始化,然后调用Application的onCreate()方法
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
而ActivityThread的main方法是整个APP的入口,没想到我们一找就找到了传世纪的源头了。从这里我们就可以理解原来我们的App在创建的时候就已经 调用了Looper.myLooper()了。
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "handleMessage: ");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.sendEmptyMessage(0);
}
}
首先我们要在activity中新建一个Handler,以便我们好找点一个切入点。这次我们的切入点就选择了较为简单的
handler.sendEmptyMessage(0);
同时,我们也在上面调用了handleMessage方法来接受我们的信息
public final boolean sendEmptyMessage(int what)
{
//调用sendEmptyMessageDelayed方法,延迟0秒
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain(); //从Message池中取出一个Message,避免构建多个Message
msg.what = what;
return sendMessageDelayed(msg, delayMillis); //调用sendMessageDelayed
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0; //防止延迟时间小于0秒
}
//将方法转换成sendMessageAtTime
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue; //取出Handler中的消息队列
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//调用消息队列的方法,将消息塞入消息队列
return queue.enqueueMessage(msg, uptimeMillis);
}
此处需要留意的一个点就是下面这句代码
msg.target = this;
这句代码是把handler绑定到了每个Message上面,这样后面每个Message就知道使用哪个handler去处理message。
好了handler中的方法我们已经看完了,其实没啥技术含量,就是跟着每个方法走就行了
刚刚我们在handler中调用了enqueueMessage方法,所以接下来我们瞅瞅enqueueMessage方法。
boolean enqueueMessage(Message msg, long when) {
··· //略去部分代码
synchronized (this) {
···//略去部分代码
msg.markInUse();
msg.when = when; // 将消息发送时间保存到message中
Message p = mMessages; //取出当前队列的第一个message,也就是最先被发送的消息
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 (;;) { //死循环,类似while(true)
prev = p; //保存列表中的上个Message
p = p.next; //取出下个Message
//如果已经到达了队列的尾端,或者上面新添加的Message的时间,小于当前的Message,则跳出死循环
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 将当前消息,插入到两个Message之间,如果是当前的消息所在的位置为队末的话,则当前消息的next为空
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;
}
其实,如果大家知道链表的话。上面的代码应该是秒懂的。
上面代码的可能有一点点难度的就是死循环那里。
那么我们假设队列中有这样的四个消息
[
A:{
when:0;
next:B},
B:{
when:100;
next:C},
C:{
when:200;
next:D}.
D:{
when:300;
next:null}
]
本来一切都很和谐,然后我们忽然来了一条Message
[
E:{
when:250;
next:null
}
]
因为很明显E.when是大于A.when的,所以程序会走入那个死循环的中。
那么循环第一次的时候
prev=A;
p=B;
when=E.when
那么E.when=250<B.when=100 么?很明显不是,所以循环继续下一步
prev=B;
p=C;
when=E.when
那么这时候 E.when=250<C.when=200 么?很明显还不是,所以循环继续下一步
prev=C;
p=D;
when=E.when
那么这时候 E.when=250<C.when=300 么?这就毋庸置疑了,所以跳出循环。
这是执行
msg.next = p; // invariant: p == prev.next
prev.next = msg;
也就等价于
E.next = D; // invariant: p == prev.next
C.next = E;
然后这时候,我们的整个队列就变成了
[
A:{
when:0;
next:B},
B:{
when:100;
next:C},
C:{
when:200;
next:E}.
E:{
when:250;
next:D}.
D:{
when:300;
next:null}
]
我们也就成功把新的消息插入了消息队列
前面我们查看源码的时候是从Activity出发,这次我们也一样,继续从activity中出发。
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "handleMessage: ");
}
};
我们查看Handler中哪个地方调用了handleMessage。
//在handler中该handleMessage 方法默认没有做任何实现
public void handleMessage(Message msg) {
}
/**
* 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);
}
}
可以看到,handleMessage方法,就是由dispatchMessage方法调用。而且在这里我们还可以看到,如果该Handler如果设置了hanldeCallback,那么就不在走handlerMessage方法。而handlerCallback的代码如下
new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
好了,我们继续看handler在哪里调用了dispatchMessage方法。于是我们在handler相关几个类中搜索一番,功夫不负有心人,我们在Looper类中发现了调用的地方
public static void loop() {
//...其他的代码
for (;;) {
Message msg = queue.next(); // might block 从消息队列中取出Message
//...其他的代码
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...其他的代码
}
}
此处我省略了无关的代码,只看主流程,可以看到,其实Looper内部其实是个死循环,不断的从queue中取出Message.然后调用Message的dispatchMessage方法。而“ queue.next(); ”方法是一个阻塞方法。这样也就是实现了整个handler流程的分析。
至于“ queue.next(); ”的具体细节,太复杂了,本宝宝看不懂,等看懂了再继续写!
这算是android源码中最简单的源码了。不由的感叹到,自己还是太菜了!
最后送大家一张我的总结图。有不足之处,欢迎大家指出!