【问题标题】:Android Looper and call stackAndroid Looper 和调用栈
【发布时间】:2011-10-22 11:49:09
【问题描述】:

我想知道 Looper 类实际上是如何处理 Looper 所附加的线程中的 Runnables(通过 Handler 类)的?如果 looper 正在循环它的 messageQueue,那么它肯定会是该线程的阻塞操作吗?我想它本身一定是在执行一些线程技巧,但是它如何将发布的 Runnables run() 方法添加到主机线程堆栈中?

很多问题!任何帮助将非常感激。谢谢!

编辑:

查看 Looper class file 类,我看到下面的内容,这让我更加困惑,因为所有 cmets 都指的是在主线程中运行的 looper,而且它在等待 MessageQueue 上的新消息时是一个阻塞操作。这怎么不阻塞 UI / 主线程???

    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        while (true) {
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);

                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf("Looper", "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.recycle();
            }
        }
    }


    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public synchronized static final Looper getMainLooper() {
        return mMainLooper;
    }

   /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }

    // sThreadLocal.get() will return null unless you've called prepare().
    private static final ThreadLocal sThreadLocal = new ThreadLocal();

    /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

【问题讨论】:

    标签: android multithreading


    【解决方案1】:

    你完全正确。调用构造 Looper.start() 的原始线程成为处理所有已发布的 Runnables 和 Messages 的线程。这确实意味着这个线程被阻塞了。

    【讨论】:

    • 虽然我理解线程执行 run() 方法,因此当时不能执行任何其他操作,但我更感兴趣的是 looper 如何检查消息队列中的任何项目线程没有阻塞(这有意义吗?)
    • Looper 处理定期检查线程上的排队消息,同时在检查之间等待(非阻塞)。
    • 如何在不使用另一个线程的情况下实现非阻塞等待?
    • 带有作业队列的循环。 IE。循环,执行作业一(检查消息),循环,执行作业二(其他),循环,作业一,等等。
    • 但是如果你的主线程只是循环并执行runnables,那肯定不会在该线程上执行任何其他操作,即无法通过调用堆栈?
    【解决方案2】:

    好的,环顾 Stack,我发现另一个问题可以回答我的问题。我的主要困惑来自this post 没有意识到以下内容。我错误地认为除了发布到处理程序(并添加到 Loopers 消息队列)的东西之外的所有东西都是在线性调用堆栈中执行的,但考虑到这更有可能是任何带有 UI 的程序是如何实现的,并制作了一个更有意义的是,UI 线程上的每一件事都源自 Looper,并且该线程上的所有执行路径都将返回它!感谢 Berdon 尝试回答我的问题,我确定我没有很好地解释我的问题 :)

    关于 android UI 线程:在某些时候(可能在任何 活动之类的创建)框架已经设置了一个Looper (包含一个消息队列)并启动它。从此, 在 UI 线程上发生的一切都是通过该循环。这 包括活动生命周期管理等。所有的回调你 override (onCreate(), onDestroy()...) 至少是间接的 从那个循环发送。例如,您可以在堆栈中看到 异常的踪迹。 (你可以试试,只要写 int a = 1 / 0; 某处 onCreate()...)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-12
      • 2011-02-17
      • 2011-10-10
      • 2023-03-30
      • 1970-01-01
      • 2014-04-19
      • 2014-03-30
      • 1970-01-01
      相关资源
      最近更新 更多