您的位置:首页 > 产品设计 > UI/UE

Handler、Looper和MessageQueue

2016-02-20 23:26 387 查看
Handler和创建它的线程绑定在一起,每个线程最多只有一个Looper对象,每个Looper只有一个MessageQueue。

当你创建一个Handler实例时,该实例就和创建它的线程、消息队列绑定。

Handler传递Messages给MessageQueue,并且在Looper从消息队列中取出时处理(通过handleMessage(Message msg)方法)。

Handler发送信息通过以下方法完成:

1.post,

2.postAtTime(Runnable, long),

3.postDelayed,

4.sendEmptyMessage,

5.sendMessage,

6.sendMessageAtTime,

7.sendMessageDelayed。

sendMessage(Message msg)方法和post(Runnable r)通过查看源码发现,最后调用的都是同一个方法。

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

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


最后到调用了sendMessageDelayed()方法。

看一下getPostMessage(Runnable r),将runnable封装到Message中,返回的是Message。

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


post(Runnable r),runnalbe是运行在和Handler绑定的线程中,并不是新开了线程运行的。如果创建Handler的线程是主线程就运行在主线程当中。

Handler在实际应用中大多都是应用于更新UI,因为必须在主线程更新UI,不能在子线程中更新。

在子线程当中更新时会报CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

看一下sendMessageDelayed方法:

[code]    public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}


又调用了sendMessageAtTime方法。

[code]   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);
}


在这里看到了MessageQueue 。

MessageQueue queue = mQueue;

这里返回到Handler的构造方法:(当你使用无参的构造方式时最终会调用该构造方法)

[code]    public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        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());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}


从这里可以看到MessageQueue 是Looper当中的MessageQueue 。

在sendMessageAtTime当中我们可以看到它调用了enqueueMessage()。

[code]     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;(可以看出msg.target是Handler),然后调用了(MessageQueue 的queue.enqueueMessage方法

加入消息队列。此处就不展开了。

Looper:用于线程轮询信息。默认线程是没有Looper的。可以调用prepare()方法来为线程创建Looper.创建有Looper线程的例子:

[code]  class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}


在主线程中创建Handler时不用调用Looper.prepare()方法是因为在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。

loop()方法,就是一直循环查询MessageQueue。

[code]    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;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

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

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycle();
    }
}


查看loop()方法的关键代码:

final Looper me = myLooper();//获取Looper

final MessageQueue queue = me.mQueue;//获取MessageQueue

for (;;) {//循环

Message msg = queue.next()//从MessageQueue当中取出Message

msg.target.dispatchMessage(msg);

// msg.target就是Handler,调用Handler的dispatchMessage方法。

msg.recycle();

}

查看Handler的dispatchMessage()方法。

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


msg.callback是什么?当你是使用Handler的post(Runnable r)系列的方法时,msg.callback=runnable。所以Handler发送信息使用的是

post()方法时调用handleCallback(msg),使用send()方法则调用的是handleMessage()。

查看handleCallback(msg)方法:

[code]    private static void handleCallback(Message message) {
    message.callback.run();
}


我们发现的是调用了Runnable的run()方法。而不是新启线程调用start()。所以Handler的post(Runnable runnable)参数runnable是运行在Handler绑定的线程,而不是新启线程运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: