阅读 1561

深入了解Android消息机制和源码分析(Java层和Native层)(下)

本文章讲解的内容是深入了解Android消息机制和源码分析(Java层和Native层),建议对着示例项目阅读文章,示例项目链接如下:

HandlerDemo

本文章分析的相关的源码基于Android SDK 29(Android 10.0,即Android Q)

由于掘金文章字数限制,分为两篇发布:

深入了解Android消息机制和源码分析(Java层和Native层)(上)

深入了解Android消息机制和源码分析(Java层和Native层)(下)

Looper

Looper用于为线程运行消息循环从MessageQueue(消息队列)中取出消息然后分发给Message(消息)对应的宿主Handler。默认情况下,线程没有与之关联的消息循环,要创建一个循环,就在运行循环的线程中调用prepare()方法,然后调用loop()方法让它处理消息,直到循环停止。

要注意的是,每一个线程只有存在一个Looper对象

Java层

成员变量

Looper类相关的成员变量,源码如下所示:

// Looper.java
// 标签
private static final String TAG = "Looper";

// 使用ThreadLocal存储Looper对象,使每个线程都能访问自己的一份Looper对象的变量副本
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// 主线程的Looper对象
@UnsupportedAppUsage
private static Looper sMainLooper;
// 当前Looper对象的观察者
private static Observer sObserver;

// 当前Looper对象的消息队列
@UnsupportedAppUsage
final MessageQueue mQueue;
// 当前Looper对象的所在的线程
final Thread mThread;

// 打印文本
@UnsupportedAppUsage
private Printer mLogging;
// 跟踪标记
private long mTraceTag;

// 如果消息分发时间超过该时间,就会显示警告日志
private long mSlowDispatchThresholdMs;

// 如果消息传递时间超过该时间,就会显示警告日志
private long mSlowDeliveryThresholdMs;
复制代码

prepare()

prepare()方法的作用是在当前线程初始化Looper对象,相关的源码如下所示:

// Looper.java
// 在普通线程中初始化Looper对象
public static void prepare() {
    // 初始化一个可以退出Looper的Looper对象
    prepare(true);
}

// 私有的Looper对象初始化方法,形式参数quitAllowed为是否退出Looper
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        // 每个线程只有一个Looper对象,否则就抛出RuntimeException异常
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // 将Looper对象存储到ThreadLocal对象
    sThreadLocal.set(new Looper(quitAllowed));
}

// 在主线程中初始化Looper对象,要注意的是,我们不需要自己手动调用这个方法来在主线程中初始化Looper对象,因为它已经被Android系统创建
public static void prepareMainLooper() {
    // 初始化一个不可以退出Looper的Looper对象
    prepare(false);
    // 取Looper的Class对象作为锁对象
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            // 如果已经在主线程创建过Looper对象,就抛出IllegalStateException异常
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        // 调用myLooper()方法拿到与当前线程关联的Looper对象,并且赋值给成员变量sMainLooper
        sMainLooper = myLooper();
    }
}

// 返回与当前线程关联的Looper对象
public static @Nullable Looper myLooper() {
    // 从ThreadLocal对象中取出与当前线程关联的Looper对象
    return sThreadLocal.get();
}

// 返回与当前线程关联的Looper对象对应的MessageQueue对象
public static @NonNull MessageQueue myQueue() {
    return myLooper().mQueue;
}
复制代码

loop()

loop()方法的作用是在当前线程中运行消息队列,源码如下所示:

// Looper.java
public static void loop() {
    // 与当前线程关联的Looper对象
    final Looper me = myLooper();
    if (me == null) {
        // 如果没有初始化Looper对象,就抛出RuntimeException异常
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 与当前线程关联的Looper对象对应的消息队列
    final MessageQueue queue = me.mQueue;

    // 得到当前线程的唯一标识(uid和pid),作用是下面每次循环都会判断线程有没有被切换
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    // 允许使用系统属性覆盖阈值,例如:adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
    final int thresholdOverride =
            SystemProperties.getInt("log.looper."
                    + Process.myUid() + "."
                    + Thread.currentThread().getName()
                    + ".slow", 0);

    boolean slowDeliveryDetected = false;

    // 循环执行
    for (;;) {
        // 从消息队列中取出消息,这有可能会阻塞线程
        Message msg = queue.next();
        if (msg == null) {
            // 如果消息是空,证明消息队列已经退出,结束循环,结束方法
            return;
        }

        // 打印日志
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
        // 确保观察者在处理事务的时候不会改变
        final Observer observer = sObserver;

        // 性能分析相关的逻辑
        final long traceTag = me.mTraceTag;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
        if (thresholdOverride > 0) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        Object token = null;
        if (observer != null) {
            // 如果观察者不为空,就调用观察者的messageDispatchStarting()方法拿到token,它会在发送消息之前调用
            token = observer.messageDispatchStarting();
        }
        long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
        try {
            // 调用宿主Handler的dispatchMessage(Message msg)方法,将消息分发给宿主Handler
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                // 如果观察者不为空,就调用观察者的messageDispatched(Object token, Message msg)方法,它会在消息被处理的时候调用
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                // 如果发生异常,并且观察者不为空,就调用观察者的dispatchingThrewException(Object token, Message msg, Exception exception)方法,它会在处理消息时引发异常的时候调用
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            // ThreadLocalWorkSource是用于跟踪是谁触发了这个线程上当前执行的工作,调用store(long token)方法,使用提供的令牌恢复状态
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                // 性能分析相关的逻辑
                Trace.traceEnd(traceTag);
            }
        }
        if (logSlowDelivery) {
            // 如果消息传递时间超过该时间,就会显示警告日志
            if (slowDeliveryDetected) {
                if ((dispatchStart - msg.when) <= 10) {
                    Slog.w(TAG, "Drained");
                    slowDeliveryDetected = false;
                }
            } else {
                if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                        msg)) {
                    // Once we write a slow delivery log, suppress until the queue drains.
                    slowDeliveryDetected = true;
                }
            }
        }
        if (logSlowDispatch) {
            // 如果消息分发时间超过时间,就会显示警告日志
            showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
        }

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

        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.recycleUnchecked();
    }
}
复制代码

quit()

quit()的作用是退出Looper,源码如下所示:

// Looper.java
// 退出Looper,要注意的是,在Looper被要求退出后,任何向消息队列发送消息的尝试都是将失败,例如:sendMessage(Message msg)方法返回false
public void quit() {
    mQueue.quit(false);
}

// 安全退出Looper,要注意的是,在Looper被要求退出后,任何向消息队列发送消息的尝试都是将失败,例如:sendMessage(Message msg)方法返回false
public void quitSafely() {
    mQueue.quit(true);
}
复制代码

调用到MessageQueue的**quit(boolean safe)**方法,这个方法前面解释过了,这里不再赘述。

Native层

Looper.h文件中定义了三个结构体,分别是请求(Request)结构体响应(Response)结构体信封(MessageEnvelope)结构体,源码如下所示:

// system/core/libutils/include/utils/Looper.h
// 请求结构体
struct Request {
    // 文件描述符
    int fd;
    // 当前事件发生的标识符,数值大于等于0或者是POLL_CALLBACK(-2)
    int ident;
    // 要监听的文件类型,默认是EVENT_INPUT,前面解释过,这里不再赘述
    int events;
    int seq;
    // 当有事件发生时,会回调该callback函数
    sp<LooperCallback> callback;
    // 文件描述符里的数据
    void* data;

    void initEventItem(struct epoll_event* eventItem) const;
};

// 响应结构体
struct Response {
    // 文件类型,默认是EVENT_INPUT,前面解释过,这里不再赘述
    int events;
    // Request对象
    Request request;
};

// 信封结构体
struct MessageEnvelope {
    MessageEnvelope() : uptime(0) { }

    MessageEnvelope(nsecs_t u, sp<MessageHandler> h, const Message& m)
        : uptime(u), handler(std::move(h)), message(m) {}

    // 发信时间
    nsecs_t uptime;
    // 信封接受者
    sp<MessageHandler> handler;
    // 信封内容
    Message message;
};
复制代码

构造函数

Looper.cpp文件部分的源码如下所示:

// system/core/libutils/Looper.cpp
// 每次迭代检索轮询事件所需的文件描述符的最大数量是16
static const int EPOLL_MAX_EVENTS = 16;

// Looper的构造函数
Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(0),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    // eventfd(unsigned int __initial_value, int __flags)函数用来创建一个事件对象,它返回一个文件描述符来代表这个事件对象,我们可以使用它来调用对象,这里是创建一个唤醒事件的文件描述符
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    // AutoMutex _l函数的作用是对mLock加锁,执行完成后自动释放锁,它利用了C++的构造函数和析构函数的自动加锁和自动释放锁
    AutoMutex _l(mLock);
    // 重建mPoll事件
    rebuildEpollLocked();
}
复制代码

Looper构造函数里执行的逻辑前面解释过了,这里就不再赘述。

sendMessage开头系列函数

源码如下所示:

// system/core/libutils/Looper.cpp
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    // 获得系统时间
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    // 调用Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message)函数
    sendMessageAtTime(now, handler, message);
}

void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
        const Message& message) {
    // 获得系统时间
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    // 调用Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message)函数
    sendMessageAtTime(now + uptimeDelay, handler, message);
}

void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message) {
#if DEBUG_CALLBACKS
    ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
            this, uptime, handler.get(), message.what);
#endif

    size_t i = 0;
    {
        // 加锁
        AutoMutex _l(mLock);

        size_t messageCount = mMessageEnvelopes.size();
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            // 按着时间顺序统计索引i
            i += 1;
        }

        // 创建信封,并且传入对应的参数
        MessageEnvelope messageEnvelope(uptime, handler, message);
        // 根据索引i将信封插入到信封向量(Vector,	它是一个封装了动态大小数组的顺序容器)
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);

        if (mSendingMessage) {
            // 如果当前正在发送消息,就不再调用wake()函数唤醒poll循环,结束函数
            return;
        }
    }
    // 释放锁

    if (i == 0) {
        // 如果i等于0,说明该消息插入到信封向量的头部,调用wake()函数唤醒poll循环
        wake();
    }
}
复制代码

回调类

LooperCallback类的源码如下所示:

// system/core/libutils/include/utils/Looper.h
class LooperCallback : public virtual RefBase {
protected:
    // LooperCallback()函数是虚析构函数
    virtual ~LooperCallback();

public:
    // 处理给定的文件描述符的poll事件,它提供与之关联的文件描述符,被触发的poll事件的位掩码(通常是EVENT_INPUT)和最初提供的数据指针
    virtual int handleEvent(int fd, int events, void* data) = 0;
};
复制代码

SimpleLooperCallback类继承LooperCallback类,SimpleLooperCallback类的源码如下所示:

// system/core/libutils/include/utils/Looper.h
class SimpleLooperCallback : public LooperCallback {
protected:
    // SimpleLooperCallback()是虚析构函数
    virtual ~SimpleLooperCallback();

public:
    SimpleLooperCallback(Looper_callbackFunc callback);
    // handleEvent(int fd, int events, void* data)是虚函数
    virtual int handleEvent(int fd, int events, void* data);

private:
    // 回调函数
    Looper_callbackFunc mCallback;
};
复制代码

看下**handleEvent(int fd, int events, void* data)**函数,源码如下所示:

// system/core/libutils/Looper.cpp
int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
    // 调用回调函数
    return mCallback(fd, events, data);
}
复制代码

Handler

Handler用于处理消息向消息池发送消息事件处理消息事件

Java层

构造方法

看下Handler构造方法,源码如下所示:

// Handler.java
// 默认构造方法,用于将该Handler与当前线程的Looper对象相关联
public Handler() {
    this(null, false);
}

// 构造方法,用于将该Handler与当前线程的Looper对象相关联,并且接受一个可以处理消息的回调接口,参数callback可以为空
public Handler(@Nullable Callback callback) {
    this(callback, false);
}

// 构造方法,用于将该Handler与传递进来的Looper对象相关联,参数looper不可为空
public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

// 构造方法,用于将该Handler与传递进来的Looper对象相关联,并且接受一个可以处理消息的回调接口,参数looper不可为空,参数callback可为空
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
    this(looper, callback, false);
}

// 构造方法,用于将该Handler与当前线程的Looper对象相关联,并且设置Handler是否应该是异步,Handler在默认情况下是同步的,调用该方法可以构造异步的Handler,要注意的是,该方法不支持外部应用使用
public Handler(boolean async) {
    this(null, async);
}
复制代码

上面的构造方法最终会调用以下两个方法,源码如下所示:

// Handler.java
public Handler(@Nullable 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());
        }
    }

    // 得到当前线程的Looper对象
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        // 如果当前线程的Looper对象为空,也就是Looper还没初始化,就抛出RuntimeException异常
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    // 得到当前线程的Looper对象所对应的MessageQueue
    mQueue = mLooper.mQueue;
    // 将形式参数callback赋值给给成员变量mCallback
    mCallback = callback;
    // 将形式参数asyn赋值给成员变量mAsynchronous
    mAsynchronous = async;
}

// 使用传递进来的Looper对象,而不是使用默认的,并且接受一个处理消息的回调接口,还要设置Handler是否应该是异步的,需要注意的是,该方法不支持外部应用使用
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
复制代码

发送消息

发送消息主要分为两类方法:

  • post开头的方法
  • sendMessage开头的方法

看下相关的源码,源码如下所示:

// Handler.java
// 将传递进来的Runnable添加到消息队列的尾部,该Runnable将在附加在该Handler的线程上运行
public final boolean post(@NonNull Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}

// 将传递进来的Runnable添加到消息队列的尾部,并在uptimeMillis时间内运行,该Runnable将在附加在该Handler的线程上运行
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

// 将传递进来的Runnable添加到消息队列的尾部,并在uptimeMillis时间内运行,token是个令牌,它为了在调用removeCallbacksAndMessages(Object token)方法可以删除消息队列中对应的消息,该Runnable将在附加在该Handler的线程上运行
public final boolean postAtTime(
        @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

// 将传递进来的Runnable添加到消息队列的尾部,并在delayMillis的时间后运行,该Runnable将在附加在该Handler的线程上运行
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

// 将传递进来的Runnable添加到消息队列的尾部,并在delayMillis的时间后运行,同时设置该消息的消息类别what,该Runnable将在附加在该Handler的线程上运行,要注意的是,该方法不支持外部应用调用
public final boolean postDelayed(Runnable r, int what, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
}

// 将传递进来的Runnable添加到消息队列的尾部,并在delayMillis的时间后运行,token是个令牌,它为了在调用removeCallbacksAndMessages(Object token)方法可以删除消息队列中对应的消息,该Runnable将在附加在该Handler的线程上运行
public final boolean postDelayed(
        @NonNull Runnable r, @Nullable Object token, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}

// 将传递进来的Runnable添加到消息队列的头部,该Runnable将在附加在该Handler的线程上运行
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
    return sendMessageAtFrontOfQueue(getPostMessage(r));
}

// 将传递进来的Message添加到消息队列的尾部
public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

// 添加一条空的普通消息到消息队列的尾部,并且设置该消息的消息类别what
public final boolean sendEmptyMessage(int what)
{
    return sendEmptyMessageDelayed(what, 0);
}

// 添加一条空的延时delayMillis的普通消息到消息队列的尾部,并且设置该消息的消息类别what
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

// 添加一条空的uptimeMillis时间内运行的普通消息到消息队列的尾部,并且设置该消息的消息类别what
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

// 添加一条延时delayMillis的普通消息到消息队列的尾部
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

// 添加一条uptimeMillis时间内运行的普通消息到消息队列的尾部
public boolean sendMessageAtTime(@NonNull 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);
}

// 添加一条普通消息到消息队列的头部
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
    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, 0);
}

// 如果在该Handler对应的同一个线程上调用该消息,就同步执行该消息,否则,调用sendMessage(Message msg)方法将其添加到消息队列中,如果消息成功运行或者成功添加到消息队列中,就返回true,否则,就返回false,这通常是因为处理消息的Looper退出
public final boolean executeOrSendMessage(@NonNull Message msg) {
    if (mLooper == Looper.myLooper()) {
        dispatchMessage(msg);
        return true;
    }
    return sendMessage(msg);
}
复制代码

可以发现post开头的方法都调用getPostMessage(Runnable r)方法或者getPostMessage(Runnable r, Object token)方法,其实post开头的方法本质上和sendMessage开头的方法一样的,都是添加一条普通消息到消息队列中,源码如下所示:

// Handler.java
// 从消息池中取出消息,并且设置该消息的callback为传进来的Runnable,最后返回该消息
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

// 从消息池中取出消息,并且设置该消息的obj为传递进来的令牌token,callback为传递进来的Runnable,最后返回该消息
@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}
复制代码

以上发送消息的方法最后会调用sendMessageAtTime(Message msg, long uptimeMillis)方法或者sendMessageAtFrontOfQueue(Message msg)方法,然后这两个方法会调用enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法,最后这个方法会调用MessageQueue的**enqueueMessage(Message msg, long when)**方法,前面提到过了,这里就不再赘述了,源码如下所示:

// Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    // 将消息的接受者设置为本身
    msg.target = this;
    // 设置消息进入队列的uid
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        // 如果是异步的,就设置消息为异步消息
        msg.setAsynchronous(true);
    }
    // 调用MessageQueue的enqueueMessage(Message msg, long when)方法
    return queue.enqueueMessage(msg, uptimeMillis);
}
复制代码

dispatchMessage(Message msg)

dispatchMessage(Message msg)方法的作用是分发消息,源码如下所示:

// Handler.java
public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        // 如果msg.callback不为空,也就是通过post开头的方法添加消息到消息队列中的,就调用handleCallback(Message message)方法
        handleCallback(msg);
    } else {
        // 如果msg.callback为空,也就是通过sendMessage开头的方法添加消息到消息队列中,就执行以下逻辑
        if (mCallback != null) {
            // 如果成员变量mCallback不为空,说明Handler设置了Callback,就调用mCallback的handleMessage(Message msg)方法
            if (mCallback.handleMessage(msg)) {
                // 如果handleMessage(Message msg)方法返回true,就说明该消息已经被拦截,不需要再进一步处理,结束方法
                return;
            }
        }
        // 如果handleMessage(Message msg)方法返回false,就说明该消息没被拦截,需要进一步处理,调用handleMessage(Message msg)方法
        handleMessage(msg);
    }
}
复制代码

如果是通过post开头的方法添加消息消息队列中,最后会调用**handleCallback(Message message)**方法,源码如下所示:

// Handler.java
private static void handleCallback(Message message) {
    // 调用消息的Runnable的run()方法
    message.callback.run();
}
复制代码

如果是通过sendMessage开头的方法添加消息消息队列中,最后会调用Handler的内部接口Callback的handleMessage(Message msg)方法或者handleMessage(Message msg)方法,这两个方法需要开发者自己去实现,源码如下所示:

// Handler.java
public interface Callback {
    // 该方法需要开发者自己去实现,如果该方法返回true,就说明该消息已经被拦截;如果该方法返回false,就说明该消息没被拦截,需要进一步处理
    boolean handleMessage(@NonNull Message msg);
}

// 该方法需要开发者自己去实现
public void handleMessage(@NonNull Message msg) {
}
复制代码

处理Message的优先级

处理Message优先级从上到下优先级从低到高,如下所示:

  • Handler的handleMessage(Message msg)方法:通过sendMessage开头的方法添加**Message(消息)MessageQueue(消息队列)**中。
  • Handler的内部接口Callback的handleMessage(Message msg)方法:通过构造方法设置Handler的内部接口Callback
  • Message的成员变量callback(Runnable)的run()方法:通过post开头的方法添加Message到**MessageQueue(消息队列)**中。

obtainMessage系列方法

obtainMessage系列方法的作用是从消息池中取出消息,源码如下所示:

// Handler.java
// 从消息池中取出消息
@NonNull
public final Message obtainMessage()
{
    return Message.obtain(this);
}

// 从消息池中取出消息类别是what的消息
@NonNull
public final Message obtainMessage(int what)
{
    return Message.obtain(this, what);
}

// 从消息池中取出消息类别是what,并且消息内容是obj的消息
@NonNull
public final Message obtainMessage(int what, @Nullable Object obj) {
    return Message.obtain(this, what, obj);
}

// 从消息池中取出消息类别是what,并且带有参数arg1和参数arg2的消息
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2)
{
    return Message.obtain(this, what, arg1, arg2);
}

// 从消息池中取出消息类别是what,并且带有参数arg1和参数arg2,同时消息内容是obj的消息
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
    return Message.obtain(this, what, arg1, arg2, obj);
}
复制代码

以上方法最后都是调用了Message类obtain系列方法,它们的作用是从消息池中返回一个新的消息对象避免重新分配新的消息对象,这些系列的方法前面解释过,这里就不再赘述。

删除消息

删除消息分为两类方法

  • removeCallbacks系列方法
  • removeMessages系列方法

源码如下所示:

// Handler.java
// 删除消息队列中的Runnable普通消息
public final void removeCallbacks(@NonNull Runnable r) {
    mQueue.removeMessages(this, r, null);
}

// 删除消息队列中带有令牌token的Runnable普通消息
public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
    mQueue.removeMessages(this, r, token);
}

// 删除消息队列中消息类别是what的普通消息
public final void removeMessages(int what) {
    mQueue.removeMessages(this, what, null);
}

// 删除消息队列中消息类别是what,消息内容是object的普通消息
public final void removeMessages(int what, @Nullable Object object) {
    mQueue.removeMessages(this, what, object);
}

// 删除消息队列中所有带有令牌token的普通消息,要注意的是,如果形式参数token传递的是空,就会删除消息队列中所有普通消息
public final void removeCallbacksAndMessages(@Nullable Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
}
复制代码

可以发现removeCallbacks系列方法最后和removeMessages系列方法是调用是MessageQueueremoveMessages(Handler h, int what, Object object)方法,它的作用是删除消息队列中符合条件的普通消息,这个方法前面解释过,这里就不再赘述。

Native层

MessageHandler类的源码如下所示:

// external/webrtc_legacy/webrtc/base/messagehandler.h
class MessageHandler {
 public:
  // MessageHandler()函数是虚析构函数
  virtual ~MessageHandler();
  // onMessage(Message* msg)是虚函数
  virtual void OnMessage(Message* msg) = 0;

 protected:
  MessageHandler() {}

 private:
  RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};
复制代码

WeakMessageHandler类继承MessageHandler类,WeakMessageHandler类的作用是持有对MessageHandler的弱引用的简单代理WeakMessageHandler类的源码如下所示:

// system/core/libutils/include/utils/Looper.h
class WeakMessageHandler : public MessageHandler {
protected:
    // WeakMessageHandler()函数是虚析构函数
    virtual ~WeakMessageHandler();

public:
    WeakMessageHandler(const wp<MessageHandler>& handler);
    // handleMessage(const Message& message)函数是虚函数
    virtual void handleMessage(const Message& message);

private:
    wp<MessageHandler> mHandler;
};
复制代码

看下**handleMessage(const Message& message)**函数,源码如下所示:

// system/core/libutils/Looper.cpp
void WeakMessageHandler::handleMessage(const Message& message) {
    sp<MessageHandler> handler = mHandler.promote();
    if (handler != nullptr) {
        // 如果MessageHandler强指针不为空,就调用MessageHandler的handleMessage(const Message& message)函数
        handler->handleMessage(message);
    }
}
复制代码

为什么主线程不会因为Looper.loop()方法里的死循环卡死?

在解答这个问题之前,先解释下进程线程的概念:

进程代码在数据集合上的一次运行活动,它是系统进行资源分配调度基本单位一个进程至少有一个线程线程是进程中的实体线程本身是不会独立存在的进程中多个线程可以共享进程的资源(例如:内存地址、文件I/O等)也可以独立调度

每个应用进程都从一个名为Zygote的现有进程分叉(fork)系统启动并加载通用框架(Framework)代码和资源(例如:Activity主题背景)时,Zygote进程随之启动,为了启动新的应用进程,系统会分叉(fork)Zygote进程,然后在新进程加载并运行引用代码,这种方法可以让框架(Framework)代码资源分配的大多数RAM页面所有应用进程之间共享,大多数情况下,应用程序都运行在一个进程中,我们也可以在AnroidManifest.xml(清单文件)设置android:process属性或者通过native代码分叉(fork)进程创建多个进程,如果想深入了解,可以看下Android的内存管理这篇文章。

Java语言统一处理了不同硬件和操作系统平台线程操作一个线程是一个已经执行start()方法而且还没结束的java.lang.Thread类的实例,其中Thread类的所有关键方法都是本地方法(Native Method)来的,这意味着这些方法没有使用或者无法使用平台相关的手段来实现

Linux中,进程线程除了是否共享资源外,并没有本质的区别,对于CPU来说就是一段可执行的代码,它们都是一个task_struct结构体CPU采用完全公平调度器(Completely Fair Scheduler,简称CFS)算法,这个算法可以保证每个任务都尽可能公平地享有CPU时间片

因为线程一段可执行的代码,当线程执行完成后,也就是可执行的代码执行完成后,线程运行状态就进入结束(Terminated)状态,然后线程就会终止,对于主线程来说,系统不希望主线程运行一段时间后主线程就会终止,那如何让主线程不被终止呢?可以让可执行的代码一直执行下去死循环就是它的实现方法,它可以保证线程不被终止Binder线程也是使用死循环这种方法,不断与Binder驱动进行读操作或者写操作,当然并非简单地死循环,这里涉及到Linuxpipe/epoll机制,在主线程中,当MessageQueue(消息队列)没有Message(消息)时,就会阻塞MessageQueue类的next()方法的nativePollOnce()方法中,这个时候主线程就会释放CPU资源进入休眠状态直到下一个消息到达或者有事务发生通过往pipe管道写端写入数据来唤醒主线程工作epoll是一种当文件描述符内核缓冲区不是空的时候,发出可读信号进行通知;当写缓冲区还没满的时候,发出可写信号的进行通知的机制,它是一种I/O多路复用机制,可以同时监控多个文件描述符Looper类的loop()方法也不会导致应用卡死,导致卡死的原因是Activity生命周期方法操作时间过长,导致掉帧,甚至导致应用无响应(ANR),所以,主线程在大多数时候是空闲状态的并不会消耗大量CPU资源也不会导致应用卡死

总结

开发者通过调用Handlerpost开头的方法或者sendMessage开头的方法添加Message(消息)MessageQueue(消息队列)中,通过调用Looperloop()方法不断从MessageQueue中取出达到触发条件的Message,然后调用宿主HandlerdispatchMessage(Message msg)方法,根据条件判断,如果是通过post开头的方法添加MessageMessageQueue中,就调用Runnablerun()方法;如果是通过sendMessage开头的方法添加MessageMessageQueue中,先判断是否通过构造方法设置Handler的内部接口Callback,如果设置了,就调用Handler的内部接口CallbackhandleMessage(Message msg)方法让开发者处理Message;如果没有设置,就调用handleMessage(Message msg)方法让开发者处理Message,要注意的是,当MessageQueue没有Message时,就会处于空闲状态,调用MessageQueue的内部接口IdleHandler的**queueIdle()**方法。

MessageQueue是连接Java层Native层的纽带,Java层MessageQueueNative层MessageQueue是通过JNI(Java Native Interface)建立关联,Java层可以向MessageQueue添加MessageNative层也可以向MessageQueue添加MessageMessageLooperHandler三个类Java层Native层之间没有任何关联,它们都在各自层实现相似的逻辑彼此是独立的Native层NativeMessageQueue类继承Native层MessageQueue类,Native层WeakMessageHandler类继承MessageHandler类。

要注意的是,消息处理步骤如下所示:

  1. 处理Native层的Message
  2. 处理Native层的Request
  3. 处理Java层的Message

题外话

Android消息机制中,可以看到使用ThreadLocal存储Looper对象,这里我想讲解下线程局部存储(TLS)

线程局部存储(TLS)

线程局部存储(TLS)是一种存储持续期(Storage Duration),对象的存储在线程开始时分配线程结束时回收每个线程都有该对象自己的实例

C中,使用关键字**_Thread_local来定义线程局部变量**,在头文件<thread.h>定义thread_local为该关键字同义,代码如下所示:

#include <threads.h>
thread_local int foo = 0;
复制代码

C++中,使用关键字thread_local来定义线程局部变量

Java中,使用ThreadLocal类来提供线程局部变量普通变量可以被任何一个线程读或者写而ThreadLocal创建的变量只能被当前线程读或者写其他线程无法读或者写该变量ThreadLocal类内部类ThreadLocalMap采用开放地址法解决哈希冲突,如果想深入了解,可以看下Java集合框架——Android中的HashMap源码分析这篇文章的题外话

我的GitHub:TanJiaJunBeyond

Android通用框架:Android通用框架

我的掘金:谭嘉俊

我的简书:谭嘉俊

我的CSDN:谭嘉俊

文章分类
Android
文章标签