Android中的Handler机制源码解析(带图解)

在Android面试的过程中,Handler机制是一个必问的问题,而其中的源码更是面试官喜欢用来当做面试题考察面试者分析源码的能力。(我深受其害啊!所以痛下决心花了一段时间搞定他)

Handler主要涉及到Handler,Looper,ThreadLocal,MessageQueue和Message。以下是自己的理解加上源码的分析做出的一些总结,不对之还请指正。


1.涉及主要的五个对象

Looper:扮演消息循环的角色,持有MessageQueue对象

ThreadLocal:用于保存looper对象,looper对象持有MessageQueue

Handler:操作Message消息的类

MessageQueue:消息队列,保存要传递的消息msg的对象

Message: 消息对象,保存要传递的信息和handler对象


2.Handler的执行过程

先给出一张自己动手画好的图:


1).ActivityThread:

      在Activity中,会创建ActivityThread线程,也就是我们说的主线程,在这个线程中,调用Looper.perpare()方法;

2).Looper.prepare():

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));
}

     1.创建Looper对象,其实在looper对象中创建了MessageQueue消息队列对象

     2.将looper对象通过set方法保存在ThreadLocal当中,其中的looper持有了MessageQueue的对象


3).mHandler.sendMessage(Message msg);

本质上会调用sendMessageAtTime(),其实post方法也是调用这个方法。

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);
}

而在enqueueMessage()方法中
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
本质上就是将msg添加到queue中,也就是说,sendMessage()方法最终的目的是将Mssage对象添加到MessageQueue消息队列中。

     这个是子线程中发送消息时候调用的。


4).Looper.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;
        .....

        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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
          .....
        }


     1.第二行,调用Looper的静态方法myLooper(),本质上是取出ThreadLocal中的保存的Looper对象,这样就保证整个体系中只有一个Looper对象;

 final Looper me = myLooper();

     2.for是一个死循环,调用取出的Looper对象中的Message里面的next()方法,不断的接收从子线程的handler发送过来的消息,而next()是一个阻塞方法,没有消息的时候停在这里,只有子线程调用sendMessageAtTime()方法后才能往下执行;

Message msg = queue.next(); // might block

      3.next()方法执行后得到Message对象,调用Handler的dispatchMessage方法,实际上就是try里面的这句

 msg.target.dispatchMessage(msg);

这个方法会调用我们在创建Handler对象时重写的handleMessage方法,handlerMessage就得到了Message,我们这样就取出了子线程的msg,整个过程就已经完成。


3.怎么从主线程往子线程发送消息?

     其实很简单,在要接收消息的线程(子线程)中调用prepare()和loope()方法,并创建Handler对象,然后在主线程发送消息就可以了。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值