Handler 机制

Handler

因为 Android 只允许在主线程更新 UI ,所以我们在子线程获取到的数据需要切换线程到主线程再做 UI 处理,而 Handler 是一种用于线程间消息传递的机制,能够实现线程切换的功能。

基本使用方式

步骤一: 创建 Handler 实例

 // callback 方式
private Handler callbackHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        // 更新UI等操作
        return true;
    }
});

// 成员内部类
private Handler innerHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // 更新UI等操作
    }
};

// 静态自定义 Handler 内部类
private static class MyHandler extends Handler {

    private WeakReference<MainActivity> mReference;

    public MyHandler(MainActivity activity) {
        mReference = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        // 更新UI等操作
        if (mReference.get() != null) {
            switch (msg.what) {
                case 0:
                    Toast.makeText(mReference.get(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
                    break;
                case 1:
                    Toast.makeText(mReference.get(), "这是空消息方式", Toast.LENGTH_SHORT).show();
                    break;
                case 2:
                    Toast.makeText(mReference.get(), "这是延时空消息方式", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }
}

总结:通常使用自定义静态内部类的方式来使用,能够避免内存泄漏。

步骤二: 调用 Handler 相关send 或 post 方法

 // 子线程中发送消息
new Thread(new Runnable() {
    @Override
    public void run() {
        Message message = Message.obtain();
        message.what = 0;
        message.arg1 = 100;
        message.obj = "普通消息方式";

        // send 方式发送普通消息和延时消息
        mMyHandler.sendMessage(message);
        mMyHandler.sendMessageDelayed(message, 2000);

        // 发送空消息
        mMyHandler.sendEmptyMessage(1);
        mMyHandler.sendEmptyMessageDelayed(2, 5000);

        // post 方式发送普通消息
        mMyHandler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Runnable 消息方式", Toast.LENGTH_SHORT).show();
            }
        });

        // post 方式发送延时消息
        mMyHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Runnable 延时消息方式", Toast.LENGTH_SHORT).show();
            }
        }, 1000);
    }
}).start();

步骤三: 移除相关消息

这一步不是必须的,是为了确保避免内存泄露风险。

@Override
protected void onDestroy() {
    super.onDestroy();
    mMyHandler.removeCallbacksAndMessages(null);
}

总结: 通常发送消息的方式有 3 种,分别是 sendMessagesendEmptyMessagepost 方法,每种方式又有延时发送的方法,分别是 sendMessageDelayedsendEmptyMessageDelayedpostDelayed,延时发送的时间单位为毫秒,即多少毫秒后再发送。

源码分析

以下相关源码会省略一些跟分析无关的代码,只保留关键代码。

ActivityThread

在应用线程的入口类 ActivityThreadmain 方法中,有如下调用:

public static void main(String[] args) {

    // 创建主线程 Looper
    Looper.prepareMainLooper();
    // Looper 开始工作
    Looper.loop();

}

mian 方法中,调用了跟 Looper 相关的两个方法,接下来我们看一下 Looper 类。

Looper

先看一下 Looper 类重要的成员变量

public final class Looper {

    // ThreadLocal 绑定线程和 Looper 对象
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    // 主线程的 Looper 对象
    private static Looper sMainLooper;

    // 消息队列
    final MessageQueue mQueue;

    // 当前线程
    final Thread mThread;

}

我们先看 prepareMainLooper 相关方法:

public static void prepareMainLooper() {
    // false 表示不允许退出
    prepare(false);
    synchronized (Looper.class) {
        // 这里判断 Looper 是否已经存在了,只允许有一个
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

// 该方法主要给子线程调用
public static void prepare() {
    prepare(true);
}

private static void prepare(boolean quitAllowed) {
    // 这里判断 Looper 只允许有一个,方法只能调用一次
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // 初始化 Looper 对象并放进 ThreadLocal 里面
    sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
    // 创建消息队列
    mQueue = new MessageQueue(quitAllowed);
    // 初始化当前线程 ,线程关联从这里开始
    mThread = Thread.currentThread();
}

prepareMainLooper() 方法内容归纳:

  1. 判断 Looper 是否已经存在,存在则报异常。

  2. 初始化 Looper 对象并放进 ThreadLocal 里面。

  3. Looper 里面初始化了 MessageQueue 对象并初始化了当前线程。

现在,我们看一下 loop() 方法,:

public static void loop() {
    // 从 ThreadLocal 中获取当前线程的 Loop
    final Looper me = myLooper();
    // 如果 Looper 还没初始化,则报错
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 获取 Looper 里面的消息队列
    final MessageQueue queue = me.mQueue;
    for (;;) {// 死循环
        // 取出消息,可能会阻塞线程
        Message msg = queue.next(); // might block
        if (msg == null) {
            // 消息为空 ,结束循环
            return;
        }
        try {
            // 回调 Handler 的 dispatchMessage 方法
            msg.target.dispatchMessage(msg);
        } finally {
        }
        // 对分发了的消息进行回收操作
        msg.recycleUnchecked();
    }
}

loop() 方法里面的逻辑归纳为:

  1. 先判断 Looper 对象是否已经初始化。

  2. 在死循环里面不断调用 Looper 的成员 MessageQueuenext() 方法来获取 Message 对象。

  3. 取出的消息不为空则回调 Message 对象的成员 targetdispatchMessage 方法 ( tartget 其实就是 Handler )。

  4. 对分发了的消息进行回收操作。

Handler

Looper 中会回调 HandlerdispatchMessage 方法,那么我们先看一下 Handler 类重要的成员变量和方法:

public class Handler {

    // 当前线程对应的 Looper 
    final Looper mLooper;

    // 指向 Looper 的 MessageQueue
    final MessageQueue mQueue;

    // Callback 对象
    final Callback mCallback;

    // 是否是异步消息,默认同步
    final boolean mAsynchronous;

    // Callback 接口对象
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

    // 该方法需要子类覆写实现逻辑操作
    public void handleMessage(Message msg) {
    }

}

构造方法

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

public Handler(Callback callback) {
    this(callback, false);
}

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

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

public Handler(boolean async) {
    this(null, async);
}

public Handler(Callback callback, boolean async) { //该构造给主线程调用
    // 指向 Looper 对象    
    mLooper = Looper.myLooper();
    // 必须要有Looper,不然报异常
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    // 指向 Looper 的 mQueue
    mQueue = mLooper.mQueue;
    // 赋值回调接口对象
    mCallback = callback;
    // 赋值是否异步
    mAsynchronous = async;
}

public Handler(Looper looper, Callback callback, boolean async) {
    // 此构造给那些在子线程创建 Handler 时使用,需要主动调用 Looper.prepare() 方法
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

Handler 类主要面向开发者,所以我们需要全面掌握里面的方法。首先是构造函数,共 6 个构造函数,但是最终会往两个构造函数调用,这两个构造函数分别给主线程和子线程调用,具体看代码注释。

obtainMessage 方法

public final Message obtainMessage()
{
    return Message.obtain(this);
}

public final Message obtainMessage(int what)
{
    return Message.obtain(this, what);
}

public final Message obtainMessage(int what, Object obj)
{
    return Message.obtain(this, what, obj);
}

public final Message obtainMessage(int what, int arg1, int arg2)
{
    return Message.obtain(this, what, arg1, arg2);
} 

public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
    return Message.obtain(this, what, arg1, arg2, obj);
}

Handler 里面有多个 obtainMessage 重载方法,用于获取 Message 对象,其实内部是调用 Messageobtain 静态方法的。所以我们也可以通过 Message 的静态 obtanin 方法来获取 Message 对象,最好不要直接用 new 关键字来创建 Message 对象,原因后面会说。

发送 Message 方法

public final boolean post(Runnable r)
{
    // 延迟0秒发送
   return  sendMessageDelayed(getPostMessage(r), 0);
}

public final boolean postAtTime(Runnable r, long uptimeMillis)
{
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

public final boolean postDelayed(Runnable r, long delayMillis)
{
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

public final boolean sendMessage(Message msg)
{
    // 一般使用这个方法,延时值为0
    return sendMessageDelayed(msg, 0);
}

public final boolean sendEmptyMessage(int what)
{    
    return sendEmptyMessageDelayed(what, 0);
}

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    // 延时时间再执行,时间为毫秒单位,延时值加上系统的当前时间作为发送时间
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    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);
}

private static Message getPostMessage(Runnable r) {
    // 创建 Message 对象并把Runnable对象赋值给 Message 的 callback
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

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

Handler 里面也有很多发送消息的方法,有 3 种发送方式:

  1. post() 类型的方法,传入的是 Runnable 对象,内部会通过 getPostMessage() 方法来封装 Message 对象,并把 Runnable 对象赋值给 Messagecallback 成员对象。

  2. sendEmpty() 类型的也不需要传入 Message 对象,内部会通过 Message.obtain() 方法获取 Message 对象。

  3. send() 类型则需要外部传入 Message 对象。

无论调用何种方式发送消息,最终会调用 enqueueMessage 方法将消息对象入队,代码如下:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    // 把当前 Handler 传给 target 变量,用于分发回调
    msg.target = this;
    if (mAsynchronous) {
        // 设置为异步消息
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

该方法会调用 MessageQueueenqueueMessage 方法来将消息入队,注意方法内调用了 msg.target = this ,结合上面 Looperloop 方法,会回调 HandlerdispatchMessage() 方法, dispatchMessage() 的源码如下:

// 消息分发
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        // 如果接收的消息中,携带这一个 callback ,就执行
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            // 如果实例化 Handler 时实现了接口回调,就执行
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 执行这个方法
        handleMessage(msg);
    }
}

// 运行消息的 Callback 接口对象
private static void handleCallback(Message message) {
    message.callback.run();
}

方法归纳:

  1. 首先判断 Messagecallback 对象是否为空,由之前分析得知,当用 post 方式发送消息时,callback 则不为空,此时会运行 callbackrun 方法,即 post 传入的 Runnablerun 方法。

  2. 然后会判断 mCallback 是否为空,如果不为空,则回调 mCallbackhandleMessage 方法,此时的 mCallback 由创建 Handler 的时候通过构造方法传入,如果 handleMessage 方法返回 true ,则不执行最后的 HandlerhandleMessage 方法,如果返回 false ,则执行。

  3. 执行 HandlerhandleMessage 方法,该方法通常会被子类覆写。

总结(消息分发执行的优先级): post 的方式 > callback 方法 > 覆写方式 。

MessageQueue

上述讲到入队的时候,会调用 MessageQueueenqueueMessage 方法,我们先看一下 MessageQueue 的构造方法,只有一个构造方法,如下:

MessageQueue(boolean quitAllowed) {
    // 用来标识是否允许退出,主线程是不允许退出的,不然就会退出整个程序
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

入队方法源码如下:

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) {
        // 已经退出,直接回收 Message ,返回 false
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, 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 设置为新的链表头
            msg.next = p;
            // 将 mMessages 指向当前的链表头
            mMessages = msg;
            needWake = mBlocked;
        } else {
            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;
        }

        // 唤醒线程,native 方法,添加Message 到 C环境中的消息队列中
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

方法归纳:

  1. 判断 Messagetarget 对象,即 Handler 是否存在,不存在报异常。

  2. 判断当前 Message 是否已经在使用,是则报异常,避免重复发送同一个消息。

  3. 判断是否已经退出循环了,如果是,则直接回收 Message ,返回 false ,入队失败。

  4. 标记当前 Message 已经在使用,然后把当前 Message 插入到链表对应的位置上,按时间执行从早到晚排序。

在上述 Looperloop 方法中,会不断循环地调用 MessageQueuenext 方法来做出队处理,获取 Message 来分发回调,next 方法如下:

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; 
    //  0 表示不会阻塞,立即返回
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        // 根据 nextPollTimeoutMillis 判断是否让其处于线程阻塞状态
        // 取出一个消息 ,native方法,在C环境中创建了一个 NativeMessageQueue 数据对象
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            // 如果有消息屏障,会过滤掉后面的同步消息,找到下一个异步消息,默认都是同步消息
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    // 还没到执行时间,设置最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 时间到了,下面的逻辑是把消息从链表中取出来
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    // 把当前消息指向的下一个消息的引用置为 null,
                    msg.next = null;

                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    // 标记已经使用
                    msg.markInUse();
                    return msg;
                }
            } else {
                没有消息的时候,一直阻塞不会超时
                nextPollTimeoutMillis = -1;
            }

            // 如果调用了 quit 方法了,则返回 null ,Looper 就会结束循环
            if (mQuitting) {
                dispose();
                return null;
            }

            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // 没有 idle handlers 要处理,Looper 继续阻塞等待
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // 处理一些不紧急的任务
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        //在处理 idle handler 的时候可能会有新的消息过来, 所以需要设置为 0 立即去取一次消息,
        //当没有 idle handler 的时候会调 continue 阻塞。
        nextPollTimeoutMillis = 0;
    }
}

方法归纳:

  1. 如果没有消息或没到消息执行时间,会阻塞线程,否则唤醒线程。

  2. 获取最早的异步消息并返回。

  3. 如果调用过 quit 退出方法,则返回空,Looper 就会结束循环。

  4. 处理一些不紧急的 idle handler 任务。

注意:主线程调用 quit 方法会报异常,默认不能退出,quit 方法代码如下:

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();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);
    }
}

从源码可以看出当我们调用 quit 方法时,如果 safefalse 时,执行的是 removeAllMessagesLocked 方法,该方法主要是把 MessageQueue 消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过 sendMessageDelayed 或通过 postDelayed 等方法发送)还是非延迟消息。

safetrue 时,其内部调用的是 removeAllFutureMessagesLocked 方法,该方法只会清空 MessageQueue 消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让 Handler 去处理完成后才停止 Looper 循环。

Message

在整个 Handler 机制中,Message 就像信件一样在其中传递,作为线程消息传递的物件,我们看看 Message 类。

public final class Message implements Parcelable {

    // 让接收者知道消息是做什么的
    public int what;

    // 用来传递整型参数
    public int arg1;

    // 用来传递整型参数
    public int arg2;

    // 用来传递复杂对象
    public Object obj;

    // 标记消息被使用
    /*package*/ static final int FLAG_IN_USE = 1 << 0;

    // 标记消息是异步的
    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

    // 消息当前的标记
    /*package*/ int flags;

    // 执行的时间
    /*package*/ long when;

    // 创建Handler时,target会被赋值给对应的 Handler
    /*package*/ Handler target;

    // Handler 用 post 消息发送消息时,会被赋值
    /*package*/ Runnable callback;

    // Bundle 对象
    /*package*/ Bundle data;

    // 指向的下一个 Message ,是个链表结构
    /*package*/ Message next;

    // 消息池链表头对象
    private static Message sPool;

    // 当前消息池的消息数量
    private static int sPoolSize = 0;

    // 消息池最大维护量
    private static final int MAX_POOL_SIZE = 50; 

    public static Message obtain() {
        // 尽量用这个方法来创建消息,消息池不为null ,则直接取出来复用消息
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        // 池内没有消息对象可用,再创建一个消息对象
        return new Message();
    }

    // 回收资源
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                // 维护消息池
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

    /*package*/ boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }

    /*package*/ void markInUse() {
        flags |= FLAG_IN_USE;
    }

    // 默认 public 构造方法,但是最好不要用
    public Message() {
    }

}

Handler消息机制的工作原理总结

通过Handler发送消息,此时会将Message入队列到MessageQueue中,并且唤醒等待的Looper
Looper获取的消息会投递给对应的Handler处理

  1. 创建与线程绑定的 Looper ,同时会创建一个与之关联的 MessageQueue 用于存放消息。

  2. 开启消息循环,从 MessageQueue 中获取待处理消息,若无消息会阻塞线程。

  3. Handler 会调用 MessageQueueenqueueMessage 方法,将 Message 入队并且唤醒等待的 Looper

  4. Looper 会循环调用 MessageQueuenext 方法,将 Message 出队并回调 Messagetarget 对象的 dispatchMessage 方法对 Message 进行分发处理, target 就是对应的 Handler 对象。

时序图如下:

答疑解惑

其实以下这些疑问在上述分析中都能找到答案,这里再简要说明一下原因。

为什么 Handler 能够切换线程执行?

我们在子线程发送的消息,最终会在 Looper 所在的线程进行分发并回调,而 Looper 默认就是运行在主线程的,也就是说回调的 handleMessage() 方法是运行在主线程的,也就达到了线程切换的目的。因此,handleMessage() 方法执行的线程就是 Looper 所在的线程,而与 Handler 创建时所在的线程无关。

示例调用链:

为什么我们能在主线程直接使用 Handler,而不需要创建 Looper?

因为在程序启动的时候,系统会自动初始化 Looper 并调用 loop 方法,上述源码有讲到。

为什么创建 Message 对象推荐使用 Message.obtain()获取?

Message 类内维护了一个 Message 缓存池,用 obtain 方法时,会优先在池内取 Message 对象,达到节省开销、减少内存消耗的目的。缓存池的来源就在 MessagerecycleUnchecked 方法中,也就是在 Message对象被回收资源时,会添加到缓存池内,缓存池最大量为 50 。

子线程可以创建 Handler 吗?

可以,创建 Handler 跟线程没关系,只需按照 Handler 的构造创建即可。因为系统只在主线程自动初始化 Looper 并调用 loop 方法,所以在子线程需要主动调用 Looper.prepare() 方法创建 Looper ,然后调用 loop() 方法开始循环工作。

子线程里使用示例代码:

// 子线程中发送消息
new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        threadHandler = new Handler(Looper.myLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                Log.d("MainActivity", "当前线程名称 == " + Thread.currentThread().getName());
                return true;
            }
        });
        Looper.loop();
        Message message = Message.obtain();
        message.what = 0;
        message.obj = "普通消息方式";
        mMyHandler.sendMessage(message);
    }
}).start();

mMyHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        threadHandler.sendEmptyMessage(1);
    }
}, 2000);

Handler(Callback) 跟 Handler() 这两个构造方法的区别在哪?

上述分析有讲到,只是执行的优先级不同,callback 方法优先执行,而且如果返回 true ,还可以拦截 handleMessage 的回调。

Handler 引起的内存泄露原因以及最佳解决方案是什么?

Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。

解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息,具体代码在上述 Handler 使用示例中有。