Android Handler深入学习(源码分析)

目录:
Android Handler深入学习(源码分析)_第1张图片

1. 前言

在上一篇关于 Android Handler使用方法 的文章中学会了 Handler 的使用方法,然而又是知其然不知其所以然的状态,这次较深入的学习一下 Handler 的源码。

在分析源码之前,先来了解一下Message、MessageQueue、Looper这几个对象。

1.1 Message 消息

定义:是线程间通讯的数据单元,包含着描述信息及任意数据对象,发送到 Handler。

在实际使用中,我们在工作线程中通过 Handler.sendMessage(Message),将携带数据的 Message 信息发送给 Handler,然后再由 Handler 处理,根据不同的信息,通知主线程作出相对应的 UI 工作。

官方文档说明:

/**
 * 定义包含着描述信息及任意数据对象的可发送到 Handler 的信息。额外包含可以不被分配的两个 int 字段及一个 Object 字段。
 * 获取 Message 对象最好的方法是调用 Message.obtain() 或 调用 Handler.obtainMessage() 方法来获取,调用该方法将从可回收的对象池中获取对象。
 */
public final class Message implements Parcelable {
    /**
     * 用户定义的消息代码,以便接收者能够识别此消息。每个 Handler 都有自己的消息代码命名空间,因此不必担心你的 Handler 与其他 Handler 起冲突。
     */
    public int what;

    /**
     * 如果只需要存储几个整数值,以 arg1 和 arg2 为变量去使用 setData(Bundle) 是较低成本的替代选择方法。
     */
    public int arg1;
    public int arg2;

    /**
     * 发送给接收者的任意对象,当使用 Messager 跨进程发送消息时,如果包含着可序列化的框架类时,Message必须是非空的。使用setData()来传输数据。
     * 注意,Android 2.2发行版之前不支持此处的Parcelable对象。
     */
    public Object obj;
    ···略···

1.2 MessageQueue 消息队列

定义:用来存储 Message 的数据队列。

官方文档说明:

/**
 * 包含着一系列由 Looper 分发的 Message 的一个低级类。
 * Message 不是直接添加到 MessageQueue 中的,而是通过与 Looper 关联的 Handler 对象来添加的。
 * 你可以使用“loop.myQueue()”方法来获取当前线程的 MessageQueue 对象。
 */
public final class MessageQueue {
    private static final String TAG = "MessageQueue";
    ···略···
}

1.3 Looper 消息循环器

定义:用于为线程执行消息循环的一个类。是 MessageQueue 与 Handler 之间的通讯媒介。

官方文档说明:

/**
  * 用于为线程执行消息循环的一个类。
  * 线程默认情况下没有与之关联的消息循环;要创建一个,在将要运行循环的线程中调用 Looper.prepare(),然后调用 Looper.loop() 让它处理消息,直到循环停止。
  * 与消息循环的大多数交互都是通过 Handler 类进行的。
  * 这是一个典型的 Looper 线程实现的例子,使用 Looper.prepare() 和 Looper.loop() 方法创建一个 Handler 对象与 Looper 进行通信。
  * 
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // 在这里处理传入的消息
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }
*/
public final class Looper { /* * API 实现注意事项: * * 该类包含设置和管理基于 MessageQueue 的事件循环所需的代码。 * 影响队列状态的api应该在 MessageQueue 或 Handler 上定义,而不是在 Looper 本身上定义。 * 例如,在队列上定义空闲处理程序和同步屏障,而在 Looper 上定义线程准备、循环和退出。 */ private static final String TAG = "Looper"; ···略··· }

1.4 Message、MessageQueue、Looper之间的关系

一句话概括:
存储在 MessageQueue 中的 MessageLooper 循环分发到指定的 Handler 中进行处理。

2. Handler 通信机制原理

关于Handler的通信机制工作原理,请看 Carson_Ho大佬的 Android Handler:图文解析 Handler通信机制 的工作原理 写的超棒,图文解析,一目了然。引用其中一Handler通信流程示意图,如下:
Android Handler深入学习(源码分析)_第2张图片

Thread、Handler、Looper三者之间的数量对应关系;

  • 一个 Thread 可以有多个 Handler。
  • 但一个 Thread 只能由一个 Looper。
  • 一个 Handler 只能关联一个 Looper 对象。
  • 反之,一个 Looper 可以被多个 Handler 所关联。

3. 源码分析

根据上一篇博客中介绍的Android Handler 使用方法, 我们针对 Handler.sendMessage(msg) 方法展开分析,分为3步:

  1. 创建 Handler 对象
  2. 创建 Message 对象
  3. 分发 Message

3.1 创建 Handler 对象

创建一个 Handler 对象,也就是实例化一个 Handler 对象,在实际的使用中,我也发现有存在三种情况,分别是:

  1. 在主线程上新建一个 Handler 对象,提供应用程序的 主Looper 对象与之绑定关联。
  2. 创建一个继承于 Handler类的静态内部类,防止内存泄漏。
  3. 在子线程上创建 Handler 对象。

我将一一展开分析:

3.1.1 在主线程上新建一个 Handler 对象,提供应用程序的 主Looper 对象与之绑定关联

如下,我们在主线程中新建 Handler 对象,

//在主线程中新建 Handler 对象,并提供应用程序的 主Looper
mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //消息处理

    }
};

通过上述代码,我们创建了一个 Handler 对象,并关联应用程序的 主Looper 对象。
这个时候我们看一下 Handler类 的构造函数,如下所示:

/**
 * Use the provided {@link Looper} instead of the default one.
 * 使用提供的 Looper对象, 而不是使用默认的Looper对象
 * @param Looper 不能为 null
 */
public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

可以发现,我们提供给 Handler 的 Looper 是通过 Looper.getMainLooper() 获取的。往下看:

/**
 * 返回应用程序的 主Looper, 它存在于应用程序的主线程中。
 */
public static Looper getMainLooper() {
    synchronized (Looper.class) {
    	//返回sMainLooper, 下一步看看sMainLooper是怎么创建 Looper 对象的。
        return sMainLooper; 
    }
}

如上所诉,getMainLooper() 返回 全局变量 sMainLooper 对象,所以我们需要看 sMainLooper 是什么时候被赋值的,如下所示,在 prepareMainLooper() 方法中,sMainLooper 被 myLooper 赋值:
/**
 * 将当前线程初始化为 Looper,并将其标记为应用程序的 主Looper
 * 应用程序的 主Looper 是由 Android环境 创建的,所以永远不需要自己调用这个函数
 */
public static void prepareMainLooper() {
    //调用 prepare() 方法,如果当前线程没有 Looper 对象,就为之新创建一个 Looper 对象。
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //返回当前线程所关联的 Looper 对象。
        sMainLooper = myLooper();
    }
}

上一步 prepareMainLooper 中:调用了 prepare(false) 来创建 Looper 对象,具体如下:
private static void prepare(boolean quitAllowed) {
    //sThreadLocal.get() 返回 Looper || null,如果返回 Looper 对象,即代表已经为该线程创建了 Looper 对象,
    //从而抛出异常,提示:“每个线程只能创建一个Looper”
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //否则,调用 new Looper()方法新建一个 Looper 对象,并放入 sThreadLocal 变量中。
    sThreadLocal.set(new Looper(quitAllowed)); //quitAllowed = false
}

上一步 prepare() 中:调用了 new Looper() 方法来新创建 Looper 对象,具体如下:
private Looper(boolean quitAllowed) {
    //新建一个 MessageQueue 
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}prepareMainLooper() 方法中,如果 sMainLooper 为 null,就赋值 sMainLooper = myLooper();myLooper() 方法如下:
/**
 * 返回当前线程所关联的 Looper 对象,如果所调用的线程没有关联的 Looper 对象,就返回 null
 */
public static @Nullable Looper myLooper() {
    //获取的 Looper 对象,是在 prepare() 方法中通过 sThreadLocal.set(new Looper(quitAllowed)); 所创建的
    return sThreadLocal.get();
}

上述代码中,getMainLooper() 方法中的 sMainLooper 是通过 prepareMainLooper() 进行赋值的,具体代码分析如上所述,其流程图如下所示:
Android Handler深入学习(源码分析)_第3张图片

3.1.2 创建一个继承于 Handler类的静态内部类,防止内存泄漏

上述创建 Handler 对象的方法是 new Handler(Looper.getMainLooper()) ,通过 Looper.getMainLooper() 方法获取 Looper 对象,然后传入到 Handler 的构造函数中,构成绑定关联关系。
但在实际开发中,我们通常将 Handler 写成静态内部类的形式,如下:

//创建 Handler 对象
mHandler = new MyHandler(this);

/**
 * 将 Handler 写成静态内部类,防止内存泄露
 */
public static class MyHandler extends Handler {
    WeakReference<HandlerAddThreadActivity> weakReference;

    public MyHandler(HandlerAddThreadActivity activity) {
        weakReference = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //处理收到的信息
    }
}

思考: 疑问?根据上面的代码,我们没有传递 Looper 对象给 Handler 去绑定关联, 那 Handler 为何又能正常工作?
带着疑惑上路:

首先看一下 Handler类 的默认构造函数

/**
 * 默认构造函数将这个处理程序与当前线程的{@link Looper}关联起来。
 * 如果此线程没有looper,则此处理程序将无法接收消息,因此将引发异常。
 */
public Handler() {
    this(null, false);
}

public Handler(@Nullable Callback callback, boolean async) {
	···略···
    //返回与当前线程关联的Looper对象。如果调用线程没有关联的 Looper 对象,则返回null
    mLooper = Looper.myLooper();
    //如果 mLooper 为null,则抛出异常。
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    //获取该 Looper 的 MessageQueue
    mQueue = mLooper.mQueue;

    //callback = null && async = false
    mCallback = callback;
    mAsynchronous = async;
}

看着不明显,mLooper 是通过 Looper.myLooper() 方法获得的.
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

但这个时候我想起了 prepareMainLooper() 方法。
/**
 * 将当前线程初始化为 Looper,并将其标记为应用程序的 主Looper
 * 应用程序的 主Looper 是由 Android环境 创建的,所以永远不需要自己调用这个函数
 */
public static void prepareMainLooper() {
    //调用 prepare() 方法,如果当前线程没有 Looper 对象,就为之新创建一个 Looper 对象。
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //返回当前线程所关联的 Looper 对象。
        sMainLooper = myLooper();
    }
}

疑问解除,无论我们有没有手动添加 Looper 给 Handler, Android环境都会为我们自动创建一个主线程的主Looper对象。

总结: 我们创建的 MyHandler 静态内部类,其实也是在主线程上创建的, Android环境会为我们自动创建一个应用程序的 主Looper 对象,主线程与 主Looper 绑定关联。

3.1.3 在子线程上创建 Handler 对象

ok, 解除了刚刚的疑问,我又问自己,那在子线程创建 Handler 对象呢?
当然,如果你在子线程中新创建一个 Handler 对象,创建的方法为:

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
    	//为当前线程创建一个 Looper 
        Looper.prepare();
        
		//在子线程中创建 Handler 对象
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // 在这里处理传入的消息
            }
        };
		//开始消息循环
        Looper.loop();
    }
}

在子线程上,我们通过调用 prepare() 来为当前线程创建一个 Looper 对象

/** 将当前线程初始化为 Looper 对象,在实际开始循环之前创建并引用该 Looper 对象。
 * 请确保在调用此方法后调用 loop() 方法,并通过调用 quit() 结束它
 */
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));
}

并且在 Handler 与 Looper 构成绑定关联关系后,通过调用 Looper.loop() 方法开始消息循环。

3.2 创建 Message消息对象

关于创建 Message 对象有两种创建方法,分别是:

  1. Message myMessage = new Message();//新建一个Message 实例
  2. Message myMessage = Message.obtain();//从回收对象池中返回Message的回收实例
/**
 * 从全局池返回一个新的消息实例。允许我们在许多情况下避免分配新对象。
 */
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    //如果消息池为空,会新建一个 Message 实例
    return new Message();
}

所以获取Message最佳方法是调用 Message.obtain() 或 Handler.obtainMessage() 方法,这将从回收对象池中复用消息实例,节省系统资源。

3.3 发送消息

在工作线程中通过调用 mHandler.sendMessage(myMessage); 方法来发送消息,这一步是消息入消息队列操作,即将 Message 入 MessageQueue。

/**
 * 在当前时间之前所有挂起的消息之后, 将消息推到消息队列的末尾。它将该线程所关联的 Handler 的 handleMessage 方法中被接收消息。
 * @return 如果信息成功加入到消息队列中,返回 true,反之,入队列失败则返回 false, 失败的原因通常是因为处理消息队列的“looper”正在退出。
 */
public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

/**
 * 延时 delayMillis 将消息入消息队列,它将该线程所关联的 Handler 的 handleMessage 方法中被接收消息。
 * @return 如果信息成功加入到消息队列中,返回 true,反之,入队列失败则返回 false, 失败的原因通常是因为处理消息队列的 Looper 正在退出。
 *         注意,true的结果并不意味着将处理该消息——如果 Looper 在消息的交付时间之前退出,则该消息将被删除。
 */
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        //默认 delayMillis = 0
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

/**
 * 在指定时间入队列,深度睡眠的时间会增加额外的执行延迟。它将该线程所关联的 Handler 的 handleMessage 方法中被接收消息。
 * @param uptimeMillis 发送消息的绝对时间,使用{SystemClock # uptimeMillis}获取。       
 * @return 如果信息成功加入到消息队列中,返回 true,反之,入队列失败则返回 false, 失败的原因通常是因为处理消息队列的 Looper 正在退出。
 *         注意,true的结果并不意味着将处理该消息——如果 Looper 在消息的交付时间之前退出,则该消息将被删除。
 */
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    //获取当前 Looper 对象的消息队列
    MessageQueue queue = mQueue;
    //如果当前 Looper 对象没有消息队列,则抛出异常,返回 false, 代表消息入队列失败
    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 boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

根据消息的处理时间入消息队列指定位置(采用单链表实现:提高插入、删除消息的效率)
boolean enqueueMessage(Message msg, long when) {
    //获得当前的 Handler 对象,如果为 null, 则抛出异常
    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) {
        //如果消息队列已经停止退出,抛出异常,入队列失败,返回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) {
            //作为消息队列中新的头部,如果队列是 blocked 的状态则需要唤醒该事件队列。
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            //根据消息处理时间插入到队列的中间。通常我们不需要唤醒事件队列,除非是队列被阻止无法正常next(),并且消息是队列中最早的异步消息
            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;
                }
            }
            //将新消息添加到p消息的前面
            msg.next = p;
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

3.4 消息循环,派发消息

消息入 MessageQueue 队列后,由 Looper 循环消息队列,然后派发消息,如下所示:

/**
 * 在线程中运行消息队列,并确保调用 quit() 方法来结束消息循环
 */
public static void loop() {
    //获取当前线程关联的 Looper 对象,如果该线程没有关联的 Looper 对象,则抛出异常
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //获取该 Looper 对象的消息队列
    final MessageQueue queue = me.mQueue;

    //遍历循环消息队列
    for (;;) {
        //取出消息队列中的消息对象,如果消息队列为空,则 block 该线程。
        Message msg = queue.next(); // might block
        if (msg == null) {
            //没有消息则表明消息队列已退出,结束消息循环
            return;
        }

        ···略···

        try {
            //获取消息对应的 Handler对象,开始分发消息
            msg.target.dispatchMessage(msg);  
        } 
      
        //回收正在使用的消息
        msg.recycleUnchecked();
    }
}

/**
 * Handler 处理经 Looper 分发来的消息
 */
public void dispatchMessage(@NonNull Message msg) {
    //Message 中的 callback 不为空,说明是使用 Handler.post(Runnable r) 方法发送的消息(具体看 3.5Handler.post(Runnalbe)方法)
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //注意! 这里又有一个callback,而且是一个全局变量mCallback,这个是Handler(Callback callback, ..)构造函数中传入的, 如果你没有传入自定义的callback, 这里就为null
        if (mCallback != null) {
            //如果实例化Handler时有传入自定义的callback方法,这里会触发该自定义方法
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //排除上述条件,这里走的就是Handler.sendMessage(msg) 方法,回到我们覆写的 handlerMessage()方法
        handleMessage(msg);
    }
}

/**
 * 回收可能正在使用的消息,由 MessageQueue 和 Looper 在处理排队消息时在内部使用。
 */
void recycleUnchecked() {
    //将消息标记为正在使用,并将该消息的所有参数都重置。
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = UID_NONE;
    workSourceUid = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;
    //如果消息池的数量小于最大数量(50)的话,就当前消息插入缓存池的头结点中。
    synchronized (sPoolSync) {
    	if (sPoolSize < MAX_POOL_SIZE) {
       	 	next = sPool;
        	sPool = this;
        	sPoolSize++;
    	}
	}
}


Looper 消息循环,发送消息给指定的 Handler中(msg.target -> 指定的Handler),触发我们覆写的 handleMessage(Message) 方法。

3.5 Handler.post(Runnable r) 方法

这里补充一下关于 Handler.post(Runnable r) 方法。

/**
 * 将 Runnable 添加到消息队列中,runnable 会在该Handler关联的线程上执行。
 * @param r 将被执行的Runnable
 * 
 * @return 如果添加到队列成功返回true, 反之,返回false
 */
public final boolean post(@NonNull Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}


private static Message getPostMessage(Runnable r) {
    //获取一个消息实例,将 Runnable 赋值给 message 的 callback
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

剩下的步骤就跟 sendMessage()是一样的,入消息队列后,looper 循环消息队列,对消息进行处理派发到各自对应的Handler来处理消息。

public void dispatchMessage(@NonNull Message msg) {
    //callback 不为空,说明是使用 Handler.post(Runnable r) 方法发送的消息
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //注意! 这里又有一个callback,而且是一个全局变量mCallback,这个是Handler(Callback callback, ..)构造函数中传入的, 如果你没有传入自定义的callback, 这里就为null
        if (mCallback != null) {
            //如果实例化Handler时有传入自定义的callback方法,这里会触发该自定义方法
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //排除上述条件,这里走的就是Handler.sendMessage(msg) 方法,回到我们覆写的 handlerMessage()方法
        handleMessage(msg);
    }
}

至此,关于 Android Handler.sendMessage() 的源码就分析完了。
其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。

另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!

你可能感兴趣的:(Android,android,Handler深入学习,Handler源码分析,android多线程)