Handler与Looper方法源码解析

概述

先看一个Android中的HandlerThread是如何使用Looper的。

public class HandlerThread extends Thread {
    @Override
    public void run() {
    	......
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        ......
        Looper.loop();
        ......
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
}

在线程的run方法中调用Looper的prepare()方法进行准备工作,准备之后就可以通过Looper.myLooper获取到当前的线程的Looper了。使用然后调用loop方法进入循环处理。使用的时候非常简单。接下来分析Looper的实现。

而且可以quit来退出线程,quit方法中获取当前线程的looper,不为null会调用looper对象quit方法退出。

Looper

prepare方法

先分析一下静态的方法prepare。

public final class Looper  {
    ······
    public static void prepare() {
        prepare(true);
    }
    ······
}

对外的静态方法prepare调用私用的带有参数的prepare方法。

public final class 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));
    }
    ······
}

参数quitAllowed标识是否允许looper退出。

首先调用sThreadLocal参数获取是否有Looper。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

sThreadLocal线程的本地对象,用于保存线程相关的变量。如果从sThreadLocal获取Looper对象不为null,说明线程已经绑定了Looper,直接抛出异常。如果为从sThreadLocal获取的Looper对象为null,就创建一个Looper,并设置到sThreadLocal中。

public final class Looper {
    ······
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    ······
}

Looper的构造方法中创建MessageQueue,用于保存消息处理。并保存当前的线程到mThread变量中。

总结一下:

  • Looper.prepare()会调用私有带有参数的prepare方法 -在私有的带有参数的prepare方法中会创建Looper对象,并添加到线程的本地对象中。 -Looper的构造方法中会创建MessageQueue消息队列对象。loop方法public final class Looper { ....... 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; ······ } ....... public static @Nullable Looper myLooper() { return sThreadLocal.get(); } ...... }loop静态方法中,首先调用myLooper获取当前的线程的looper。如果为null,说明线程未绑定Looper,直接抛出异常。如果不为null,获取Looper中的消息队列MessageQueue。public final class Looper { ....... public static void loop() { ······ for (;;) { Message msg = queue.next(); // 消息队列为空,将一直阻塞 if (msg == null) { return; } ······ } ····· } }接着是死循环,一直从消息队列中获取消息message。当msg为null说明MessageQueue正在退出,这里就直接从死循环中退出。接着分析。public final class Looper { public static void loop() { for (;;) { ······ try { msg.target.dispatchMessage(msg); } finally { } ······ } ······ } }消息对象的target对象实际为Handler对象。也就是调用了Handler的dispatchMessage对象来处理消息。public final class Looper { ······ public static void loop() { ······ for (;;) { ······ msg.recycleUnchecked(); } ······ } ······ }最后是调用msg的recycleUnchecked。也是就回收msg,以备下次使用。

总结一下Looper.loop()方法:

-获取当前线程绑定的Looper的消息队列。

-死循环中不断从消息队列中取出Message来处理。有消息就调用消息的target(Handler对象)的来处理。

-最后回收Message。

quit方法

public final class Looper  {
    ······
	public void quit() {
        mQueue.quit(false);
    }
    ······
}

Looper的quit方法会调用消息队列的quit方法。

分段阅读MessageQueue的quit方法。

public final class MessageQueue {
    ······
	void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            }
            ······
        }
    }
    ······
}

MessageQueue方法中先检测mQuitAllowed用来判断是否支持退出,主线程的looper是不支持的。

检测mQuitting值来判断MessageQueue是否已经退出了。如果mQuitting为true,说明MessageQueue已经退出,就直接返回了。

如果mQuitting是false,接着执行,设置mQuitting = true,接着safe为true,说明是安全退出,会调用 removeAllFutureMessagesLocked()。我们来分析一下removeAllFutureMessagesLocked()

private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            //比较当前的message的执行的时间是否大于当前的时间。如果是就直接的移除所有的消息。
            if (p.when > now) {
                removeAllMessagesLocked();
            } else {
                Message n;
                //循环比较获取时间点大于当前的时间点的消息。
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                //循环删除消息队列中时间点大于当前时间点的消息。
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }

此方法主要是根据删除执行的时间点大于当前时间点的消息。我接着分析MessageQueue的quit方法。

void quit(boolean safe) {
	······
    synchronized (this) {
      	······
        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }
        
        nativeWake(mPtr);
    }
}

如果safe为false,不是安全退出,直接调用removeAllMessagesLocked()删除回收所有的Message。

总结一下Looper的quit方法:

-Looper的quit方法会调用消息队列MessageQueue的quit方法

-MessageQueue的quit方法中,如果是非安全退出,直接移除所有的消息。如果是安全退出直接移除执行时间点大于当前时间点的Message。

主线程中的Looper

主线程中的消息的管理也是通过Looper来实现的。它与普通线程的Looper不同的是有特殊的方法,但原理基本一致。

public final class Looper {
	private static Looper sMainLooper;  // guarded by Looper.class
	public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }
}

-主线程的Looper有单独的变量sMainLooper保存。

-prepareMainLooper方法用于准备主线的Looper,它是在ActivityThread的main方法中调用的,也就是创建主线程时就会创建了。

-getMainLooper方法获取主线程的Looper。

Handler

A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue.

从描述可以总结出Handler一些特性:

1.每个Handler实例都会与一个线程以及线程的messageQueue关联。

2.发送消息。

3.处理消息,处理Runnable。

Handler与Looper的关系图:

Handler处理机制

从上面的特性展开了三个问题:

1.Handler是如何与线程的Looper关联的?

2.Handler是如何发送消息的,发送到哪里了?

3.Handler是如何处理消息的?

我们一个一个分析。

Handler与Looper关联

Handler关联Looper其实就是在构造方法中。以默认函数为例。

public class Handler {
	public Handler() {
        this(null, false);
    }
    /**
     * @hide
     */
    public Handler(Callback callback, boolean async) {
        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;
    }
}

不传递任何参数将调用一个其他的构造方法。构造方法中直接获取Looper.myLooper()来获取当前线程的Looper,保存到mLooper中,然后获取mLooper的消息队列mQueue保存到mQueue中。保存Callback用于处理消息。最后一个是mAsynchronous,标识消息是否为异步处理。

这样就关联到了Looper。

Hanlder处理消息

我们在Looper的loop方法中分析到,处理消息时回调用Message的target的dispatchMessage方法处理,Message的target对象就是Handler对象。

msg.target.dispatchMessage(msg);

那我们来分析dispatchMessage来看看如何处理消息的。

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

-如果msg的callback不为null,就是直接调用callback的run方法。一般是通过post方法发送的Runnable。

-然后判断Handler的mCallback是否为null,不为null就调用mCallback的handleMessage的方法处理。

-最后调用Handler的handleMessage来执行。

Handler发送消息

发送消息通过两种方式:

-post相关的方法,来发送Runnable。

-sendMessage相关的方法,发送一个Message。

sendMessage方法

我们先来分析sendMessage方法

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

此方法会调用sendMessageDelayed方法,延迟的时间为0。

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

此方法又会委托给sendMessageAtTime来发送消息。

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的target对象为当前对象,用于处理msg。

并调用消息队列MessageQueue的enqueueMessage来添加到队列中去。

总结:

-sendMessage的方法最终会调用sendMessageAtTime方法,然后调用enqueueMessage()方法,而在enqueueMessage()方法中会设置message.target为此Handler,这样Looper获取到的Message可以调用message.target来处理了。

post方法

我们来分析post相关方法。

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

post方法显示通过getPostMessage获取一个Message。

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

然后通过sendMessageDelayed发送消息。

总结:

-post方法实际上就是封装成Message再发送。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券