码迷,mamicode.com
首页 > 移动开发 > 详细

Android消息机制Handler、Looper、MessageQueue源码分析

时间:2016-04-11 14:30:24      阅读:444      评论:0      收藏:0      [点我收藏+]

标签:

1. Handler Looper MessageQueue的关系

技术分享

2.源码分析

下图表示了Handler、Looper、MessageQueue、Message这四个类之间的关系。
技术分享

  • Handler必须与一个Looper关联,相关Looper决定了该Handler会向哪个MessageQueue发送Message
  • 每一个Looper中都包含一个MessageQueue
  • Handler中的mQueue引用的就是与之关联的Looper的MessageQueue
  • 不管Handler在哪个线程发送Message,其中的mCallback或handleMessage方法都会在Looper所在的线程执行
    以上几条结论将会在下面的源码分析中解释。

2.1 Handler的创建

实际使用中通常在Activity中new Handler()创建一个Handler。之前说过,Handler必须与一个Looper关联,这个构造方法怎么没有给成员变量mLooper赋值?分析以下源码,可以看到通过调用Looper.myLooper()就可以获取当前线程的Looper。若获取不成功,则会抛出RuntimeException,创建Handler失败。获取成功后,就会给Handler的成员变量mLooper和mQueue赋值。
关于Looper.myLooper()的源码分析请参见Looper源码分析

public Handler() {
    this(null, false);
}

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        // 这一块代码通过反射机制判断该继承与Handler的类是不是匿名内部类或成员类或局部类且不为static
        // 若以上条件都满足,则会提示要将该Handler设为static,否则会内存泄露
        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
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        // 若该线程没有Looper,则Handler无法创建
        throw new RuntimeException(
            "Can‘t create handler inside thread that has not called Looper.prepare()");
    }
    // Handler中的mQueue引用的就是Looper中的mQueue
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

上面两个Handler构造方法有个不足,在哪个线程调用该构造方法,该Handler就必须与当前线程的Looper进行关联,所以Handler还提供了另外一个构造方法,该构造方法不管在哪个线程调用,可以与特定的Looper进行关联,源码如下:

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

2.2 Handler向MessageQueue发送Message

Handle有两组方法向MessageQueue发送Message。

  • sendMessage
  • postRunnable

分析以下源码可知,postRunnable先是创建一个Message,并将参数Runnable赋给Message的callback成员变量。两组方法最终调用的都是sendMessageAtTime。

public final boolean post(Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    // 这里将delay时间转换为了以boot时间为基准的时间,这样所有的Message有了同样的时间基准,从而可以排序
    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调用了方法enqueueMessage。方法先将该Handler的引用赋给msg的成员变量target,该target会在消息派发的时候起作用,它标识了该消息应该交给哪个Handler处理。最后调用MessageQueue.enqueueMessage方法。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

2.3 Message的属性

在了解MessageQueue如何处理Message之前,先了解一下Message有哪些重要属性。

属性 意义
int what 用于指明消息类型
int arg1 int arg2 Object obj 用于携带参数
Messenger replyTo 用于跨进程通信
Handler target 在消息派发时用于指明哪个handler处理消息
Runnable callback 处理消息时执行的回调方法
long when 用于指明何时派发消息
Message next 指向下一个Message节点,用于构建消息链表

2.4 将Message插入MessageQueue

MessageQueue.enqueueMessage源码如下:

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(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 (;;) {
                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;
}

首先判断Message的target是否为空,是否正在被使用,MessageQueue是否处于quiting状态,若是则会抛出异常。
以下代码片段为关键逻辑。

if (p == null || when == 0 || when < p.when) {
    // 将消息插入链表头。
    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 (;;) {
        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;
}

MessageQueue为一个消息链表,节点按消息派发时刻先后的顺序排列,p为Message链表头。
当MessageQueue为空时(p == null),或消息派发时刻为0(when == 0),或消息派发时刻早于消息链表头消息的派发时刻时,就将消息插入消息链表头。
反之,则遍历链表,寻找插入位置,将该消息插入链表。

2.4 Looper消息循环并派发消息

消息循环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;
        }

        ...

        msg.target.dispatchMessage(msg);

        ...

        msg.recycleUnchecked();
    }
}

queue.next()取出消息。
msg.target.dispatchMessage(msg)相当于handler.dispatchMessage(msg),派发消息,调用目标handler回调方法dispatchMessage。

2.5 处理消息

消息处理回调方法源码如下:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

判断Message的callback是否不为空,当handler使用postRunnable时,参数Runnable就付给了msg.callback,这种情况就不为空,则会执行该callback。
判断mCallback时候为null,mCallback是Handler的成员变量,是在构造方法里赋值的,若不为空则执行mCallback.handleMessage(msg)。
当msg.callback和mCallback都为null时,执行handleMessage(msg)。

上述过程正是Android消息机制。

5. Active Object模式

通常在这样的情况下使用Handler,由于在非UI线程不能执行更新UI操作,所以在非UI线程使用Handler发送更新UI消息,Handler在UI处理消息并执行更新UI操作。这个过程其实是要将方法的调用与方法的执行解耦。
发送更新UI消息相当于方法的调用
执行更新UI操作相当于方法的执行
这正是Active Object模式要解决的问题。

Active Object的概念在《Java编程思想》第4版中有所提及

第21章 并发
21.10 活动对象

之所以称这些对象是“活动的”,是因为每个对象都维护着它自己的工作器线程和消息队列,并且所有对这种对象的请求都将进入队列排队,任何时刻都只能运行其中的一个。

一般情况下,一个对象调用其某个方法,该方法将会在当前线程中执行,即在哪个线程调用就在哪个线程执行,对象完全被动,无法控制方法的执行线程,所以一般的对象称为被动对象Passive Object。
而主动对象就不同了,它维护着自己的工作线程以及消息队列,不管在哪个线程调用主动对象的方法,调用请求都会进入队列排队,它自己的工作线程从消息队列中取出调用请求并执行,方法的调用与方法的执行解耦,并且方法的执行线程完全受自己控制,所以称为主动对象。
以Handler为例,Handler维护了一个Looper和一个消息队列MessageQueue,Looper决定了Handler在哪个线程处理消息,不管在哪个线程调用Handler.sendMessage(msg),消息处理程序都会在Looper所在线程中执行。

技术分享
在Handler这个例子中,组成结构对应关系如下:
Proxy -> Handler.sendMessage()
Scheduler -> Looper
ActivationList -> MessageQueue
MethodRequest -> Message
ConcreteMethodRequest -> 不同的消息类型
Servant -> Handler的消息处理方法handleMessage

参考资料

  1. Java编程思想第四版
  2. 面向模式的软件架构·卷2:并发和联网对象模式

Android消息机制Handler、Looper、MessageQueue源码分析

标签:

原文地址:http://blog.csdn.net/sun927/article/details/51114644

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!