一份你可能需要的用中文注释的 Looper 源码

版权声明:本文为博主原创文章,转载请注明出处,如有问题,欢迎指正,谢谢。 https://blog.csdn.net/qq_33404903/article/details/89461197
Straightforward
/**
 * 用来为一个线程运行消息循环的类。默认的线程本身是没有与之相关联的消息循环的;
 * 要创建一个的话,在将要运行循环的线程中调用 {@link #prepare},然后调用
 * {@link #loop} 来让它处理消息,直到循环停止。
 *
 *
 * <p>与消息循环的大多数交互都是通过 {@link Handler} 类进行的。
 *
 * <p>这是一个典型的 Looper 线程实现的例子,
 * 使用 {@link #prepare} 和 {@link #loop} 的分离创建一个初始的 Handler
 * 来和 Looper 交流。
 *
 * <pre>
 *  class LooperThread extends Thread {
 *      public Handler mHandler;
 *
 *      public void run() {
 *          Looper.prepare();
 *
 *          mHandler = new Handler() {
 *              public void handleMessage(Message msg) {
 *                  // 在此处理传入的消息
 *              }
 *          };
 *
 *          Looper.loop();
 *      }
 *  }</pre>
 */
public final class Looper {
    /*
     * API实现说明:
     *
     * 该类包含基于 MessageQueue 设置和管理事件循环所需的代码。
     * 影响队列状态的 APIs 应该在 MessageQueue 和 Handler 上定义,而不是在 Looper 本身上定义。
     * 例如,空闲的 Handlers 和同步障碍被定义在准备线程的队列上,循环和退出则定义在 looper 上。
     */

    private static final String TAG = "Looper";

    // sThreadLocal.get() 将返回 null,除非你调用了 prepare()。
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // 由 Looper.class 守护

    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;
    private long mTraceTag;

    /**
     * 若设置此值,如果消息调度花费的时间比它长,looper 将显示警告日志。
     */
    private long mSlowDispatchThresholdMs;

    /**
     * 若设置,如果消息传递(实际传递时间 - 到达时间)花费的时间超过此时间,looper 将显示警告日志
     */
    private long mSlowDeliveryThresholdMs;

    /**
     * 将当前线程初始化为一个 looper。
     * 这使您有机会在实际启动循环之前创建引用此 looper 的 handlers。
     * 一定要在调用这个方法之后调用 {@link #loop()},并通过调用 {@link #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));
    }

    /**
     * 将当前线程初始化为 looper,将其标记为应用程序的 main looper。
     * 应用程序的 main looper 是由 Android 环境创建的,因此您永远不需要自己调用此函数。
     * 另见:{@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * 返回应用程序的 main looper,它位于应用程序的主线程中。
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    /**
     * 在此线程中运行消息队列。务必调用{@link #quit()} 来结束循环。
     */
    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;

        // 确保此线程的标识是本地进程的标识,并跟踪该标识标记的实际内容。
        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;
            }

            // 这必须在局部变量中,以防 UI 事件设置 logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            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;
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                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)) {
                        // 一旦我们写了一个慢速传递 log,请在队列耗尽之前禁止。
                        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();
        }
    }

    private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
                                       String what, Message msg) {
        final long actualTime = measureEnd - measureStart;
        if (actualTime < threshold) {
            return false;
        }
        // 对于慢速传递,当前消息并不重要,但无论如何都要记录它。
        Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms "
                + Thread.currentThread().getName() + " h="
                + msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what);
        return true;
    }

    /**
     * 返回与当前线程关联的 Looper 对象。
     * 如果调用线程未与 Looper 关联,则返回 null。
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * 必须从运行 Looper 的线程调用它,否则将抛出 NullPointerException。
     */
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }

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

    /**
     * 如果当前线程是此 looper 的线程,则返回 true。
     */
    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }

    /**
     * 控制此 Looper 处理消息时的日志记录。
     * 如果启用,将在每个消息调度的开始和结束时将日志消息写入 printer,以标识目标 Handler 和消息内容。
     *
     * @param printer 将接收日志消息的 Printer 对象,或者为 null 以禁用消息日志记录。
     */
    public void setMessageLogging(@Nullable Printer printer) {
        mLogging = printer;
    }

    /** {@hide} */
    public void setTraceTag(long traceTag) {
        mTraceTag = traceTag;
    }

    /**
     * 设置慢速调度/传递日志的阈值。
     * {@hide}
     */
    public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
        mSlowDispatchThresholdMs = slowDispatchThresholdMs;
        mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
    }

    /**
     * 退出 looper
     * <p>
     * 将造成 {@link #loop} 方法终止,而不处理消息队列中的任何其它消息。
     * </p><p>
     * 请求 looper 退出后,任何向队列发送消息的尝试都将失败。
     * 例如,{@link Handler#sendMessage(Message)} 方法将返回 false。
     * </p><p class="note">
     * 使用此方法可能不安全,因为在 looper 终止之前可能无法传递某些消息。
     * 请考虑使用 {@link #quitSafely} 来确保所有待处理的工作都以有序的方式完成。
     * </p>
     *
     * @see #quitSafely
     */
    public void quit() {
        mQueue.quit(false);
    }

    /**
     * 安全地退出 looper。
     * <p>
     * 一旦处理了已经发送的消息队列中的所有剩余消息,就会造成 {@link #loop} 方法终止。
     * 但是,在循环终止之前,将不会发送具有未来到期时间的待处理延迟消息。
     * </p><p>
     * 请求 looper 退出后,向队列发送消息的任何尝试都将失败。
     * 例如,{@link Handler#sendMessage(Message)} 方法将返回 false。
     * </p>
     */
    public void quitSafely() {
        mQueue.quit(true);
    }

    /**
     * 获取与此 Looper 关联的线程。
     *
     * @return looper 的线程。
     */
    public @NonNull Thread getThread() {
        return mThread;
    }

    /**
     * 获取该 looper 的消息队列。
     *
     * @return 该 looper 的消息队列。
     */
    public @NonNull MessageQueue getQueue() {
        return mQueue;
    }

    /**
     * 转储 looper 的状态以进行调试。
     *
     * @param pw 用于接收转储内容的 printer。
     * @param prefix 加到打印的每一行之前的前缀。
     */
    public void dump(@NonNull Printer pw, @NonNull String prefix) {
        pw.println(prefix + toString());
        mQueue.dump(pw, prefix + "  ", null);
    }

    /**
     * 转储 looper 的状态以进行调试。
     *
     * @param pw 用于接收转储内容的 printer。
     * @param prefix 加到打印的每一行之前的前缀。
     * @param handler 仅转储此 Handler 的消息。
     * @hide
     */
    public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) {
        pw.println(prefix + toString());
        mQueue.dump(pw, prefix + "  ", handler);
    }

    /** @hide */
    public void writeToProto(ProtoOutputStream proto, long fieldId) {
        final long looperToken = proto.start(fieldId);
        proto.write(LooperProto.THREAD_NAME, mThread.getName());
        proto.write(LooperProto.THREAD_ID, mThread.getId());
        mQueue.writeToProto(proto, LooperProto.QUEUE);
        proto.end(looperToken);
    }

    @Override
    public String toString() {
        return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
                + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33404903/article/details/89461197
今日推荐