android工作原理流程图,Android源码分析--Handler机制的实现与工作原理

Handler机制在Android中是一个非常重要的知识点,在我们的平常开发中也是经常使用到的。在Android的面试中Handler机制更是必考的题目,而且题目也很单一:请说说Handler、Looper、MessageQueue之间的关系。这个问题无论是我去面试还是我面试别人,都会问到的一个问题。如果你遇到了这个问题,你只是简单的说一下它们是什么什么关系,那是远远不够的。这道题考察的无非就是你对Handler机制的实现和它的工作原理的了解。下面我们就通过Handler机制的工作流程图和源码来详细分析Handler实现细节和工作原理。

下面想看Handler的工作流程图:(第一次画图,有点丑,凑合着看吧)

f844dc373efb

Handler的工作流程.png

因为Handler的主要作用就是线程切换,所以在图中我把Handler线程变化也画了出来。从这张图我们能看出几点信息:

1、Handler负责消息的发送和处理:Handler发送消息给MessageQueue和接收Looper返回的消息并且处理消息。

2、Looper负责管理MessageQueue:Looper会不断地从MessageQueue取出消息,交给Handler处理。

3、MessageQueue是消息队列(实时上它是用链表实现的),负责存放Handler发送过来消息。

4、一个Looper对应一个线程(自己所在的线程,如:线程B)。Looper的loop()方法运行在自己所在的线程(线程B)中,当Handler在线程A发送一条消息存放到MessageQueue时,Looper的loop()方法在线程B把消息取出来,并交给Handler处理,所以Handler的处理消息的方法是运行在Looper所在的线程(线程B)的。由于多个线程之间共享内存空间,所以Handler可以在线程A把消息存放到MessageQueue,Looper可以在线程B把消息取出来,一存一取之间就实现了线程的切换。

现在我们了解了Handler的工作流程和线程切换原理。那么它在源码中又是如何去实现的呢?

从使用的角度看,我们要使用Handler首先要得到一个Handler对象,那么我们就从最简单的new Handler()作为入口,来分析它的源码。

public Handler() {

this(null, false);

}

public Handler(Callback callback, boolean async) {

//获取Looper对象

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread that has not called Looper.prepare()");

}

//获取Looper对象的mQueue属性,mQueue 就是MessageQueue对象。

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

在Handler的构造方法中,首先通过Looper.myLooper()方法获取当前线程的Looper对象,如果Looper对象为空,就抛出异常,说当前线程还没有调用Looper.prepare()方法。如果Looper不为空,Handler就会持有Looper的MessageQueue对象mQueue。

我们再看Looper.myLooper()和Looper.prepare()两个方法:

static final ThreadLocal sThreadLocal = new ThreadLocal();

//创建当前线程的Looper对象

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对象

public static @Nullable Looper myLooper() {

return sThreadLocal.get();

}

这里有一个很关键的类:ThreadLocal,它一个线程内部的数据存储类,通过它存储的数据只有在它自己的线程才能获取到,其他线程是获取不到的。所以sThreadLocal.get()获取的就是当前线程的Looper对象。在Looper.prepare()方法中我们看到了如果当前线程已经有Looper对象,就会抛出异常,说一个线程只能创建一个Looper对象,所以Looper对象与自己所在的线程是相对应的。

再看Looper的构造方法:

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

Looper的构造方法是私有的,外界不能直接创建Looper对象,只能通过Looper.prepare()方法创建对象并且通过Looper.myLooper()获取对象,这就保证了一个线程只能有一个Looper对象。Looper.prepare()不能调用两次。

在Looper的构造方法中会创建一个MessageQueue对象,这个就是负责存放消息的消息队列,也就是Handler所持有的mQueue 对象。它是由Looper创建和管理的。

看完了Handler、Looper和MessageQueue对象的创建,接着看消息的发送:

Handler发送消息的方法有很多,但无论你是send一个Message还是post一个Runnable;无论你是延时发送还是不延时发送,最终都会调用Handler的enqueueMessage()方法。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

//把this赋值给msg的target属性,this就是Handler对象。

msg.target = this;

if (mAsynchronous) {

msg.setAsynchronous(true);

}

//把消息存放到MessageQueue

return queue.enqueueMessage(msg, uptimeMillis);

}

这里直接把消息存放到MessageQueue 就完事了。那么消息又是从哪里被取出来的呢?

Looper里有一个Looper.loop()方法,我们看一下它的源码。

public static void loop() {

final MessageQueue queue = me.mQueue;

//一个死循环

for (;;) {

//从MessageQueue中取出一条消息

Message msg = queue.next();

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

//把消息交给Handler处理。

msg.target.dispatchMessage(msg);

}

}

从上面的代码中我们看到loop()会开启一个死循环,不断地从MessageQueue中取出消息并交给Handler处理。在前面的enqueueMessage()方法中我们知道了msg.target就是发送消息的Handler对象。

这里有同学可能会有疑问:上面的代码中明明如果(msg == null),就退出方法,为什么我还说loop()里面是个死循环呢?这是因为MessageQueue的next()方法取出消息的时候,如果没有消息,next()方法会阻塞线程,直到MessageQueue有消息进来,然后取出消息并返回。所以queue.next()一般不会返回null,除非调用Looper的quit()或者quitSafely()方法结束消息轮询,queue.next()才会返回null,才会结束循环。

public void quit() {

mQueue.quit(false);

}

public void quitSafely() {

mQueue.quit(true);

}

最后我们来看 一下消息的处理:Handler的dispatchMessage(msg)方法。

public void dispatchMessage(Message msg) {

//如果Message有自己的callback,就由Message的callback处理

if (msg.callback != null) {

handleCallback(msg);

} else {

//如果Handler有自己的mCallback,就由Handler的mCallback处理

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

//默认的处理消息的方法

handleMessage(msg);

}

}

处理消息的方法有三个:

1、优先级最高的是Message自己的callback,这是一个Runnable对象,我们用Handler post一个Runnable的时候,其实就是把这个Runnable赋值个一个Message对象的callback,然后把Message对象发送给MessageQueue。

2、优先级第二的是Handler自己的mCallback,在我们创建一个Handler对象的使用可以传一个Handler.Callback对象给它并实现Callback里的handleMessage(msg)方法,作为我们的消息处理方法。

3、优先级最低的是Handler自己的handleMessage(msg)方法,这也是我们最常用的消息处理方法。

到这里我们的分析就结束了,现在你对Handler机制是不是有了深刻的认识呢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值