Android的活套和调用堆栈 [英] Android Looper and call stack

查看:167
本文介绍了Android的活套和调用堆栈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道如何弯针类实际上是在线程处理的Runnable(通过Handler类)的活套连接到?如果一个活套是通过其循环的MessageQueue那么肯定,这将是该线程阻塞操作?我想它本身必须执行一些挂羊头卖狗肉穿线但它是如何添加发布的Runnable run()方法到主机线程栈?

很多问题!任何帮助将是非常美联社preciated。谢谢!

编辑:

通过尺蠖<一个展望href=\"http://$c$csearch.google.com/$c$csearch#uX1GffpyOZk/core/java/android/os/Looper.java&q=package%3aandroid.git.kernel.org%20file%3aandroid/os/Looper.java&l=1\"相对=nofollow>类文件类我看到下面的,它混淆了我更加为所有评论指在主线程,而且运行的尺蠖在等待有关的MessageQueue新邮件的阻塞操作。这是如何不堵UI /主线程?

  / **
     *运行在这个线程消息队列。一定要打电话
     * {@link #quit()}结束循环。
     * /
    公共静态最后的无效循环(){
        尺蠖我= myLooper();
        的MessageQueue队列= me.mQueue;        //确保该线程的身份是当地的过程中,
        //并跟踪是什么身份令牌实际上是。
        Binder.clearCallingIdentity();
        最终长的ident = Binder.clearCallingIdentity();        而(真){
            消息味精= queue.next(); //可能会阻止
            //如果(!me.mRun){
            //突破;
            //}
            如果(MSG!= NULL){
                如果(msg.target == NULL){
                    //没有目标是一个神奇的标识符退出消息。
                    返回;
                }
                如果(me.mLogging!= NULL)me.mLogging.println(
                        &GT;&GT;&GT;&GT;&GT;调度为+ msg.target +
                        + msg.callback +:+ msg.what
                        );
                msg.target.dispatchMessage(MSG);
                如果(me.mLogging!= NULL)me.mLogging.println(
                        &LT;&LT;&LT;&LT;&LT;成品为+ msg.target +
                        + msg.callback);                //该调度过程中确保
                //线程的标识没有损坏。
                最终长newIdent = Binder.clearCallingIdentity();
                如果(IDENT!= newIdent){
                    Log.wtf(活套,线程标识从0X改为
                            + Long.toHexString(IDENT)+来0X
                            + Long.toHexString(newIdent)+,同时指派给
                            + msg.target.getClass()。的getName()+
                            + msg.callback +什么=+ msg.what);
                }                msg.recycle();
            }
        }
    }
    / **
     *返回应用程序的主尺蠖,它生活在应用程序的主线程。
     * /
    公共同步静态最终活套getMainLooper(){
        返回mMainLooper;
    }   / **
     *返回与当前线程相关的Looper对象。返回
     * NULL如果调用线程不与活套有关。
     * /
    公共静态最后的活套myLooper(){
        返回(活套)sThreadLocal.get();
    }    // sThreadLocal.get()将返回null,除非你叫prepare()。
    私有静态最后的ThreadLocal sThreadLocal =新的ThreadLocal();    / **初始化当前线程作为一个活套。
      *这给你一个机会,建立处理程序然后引用
      *此尺蠖,实际开始循环之前。一定要打电话
      * {@link #LOOP()}调用此方法后,并通过调用它结束
      * {@link #quit()}。
      * /
    公共静态最终无效prepare(){
        如果(sThreadLocal.get()!= NULL){
            抛出新的RuntimeException(只有一条环线可以每个线程创建);
        }
        sThreadLocal.set(新活套());
    }


解决方案

好吧,看着周围堆栈,我发现一个问题,回答我的。我的主要困惑是从没有从<一个实现未来下方href=\"http://stackoverflow.com/questions/5193913/handlers-messagequeue-looper-do-they-all-run-on-the-ui-thread\">this帖子。我被错误地以为一切的除了张贴到处理程序的东西(并加入到活套的MessageQueue)正在以线性调用栈执行,但​​考虑它,这是更可能如何与一个UI任何程序被执行,并且使一个更有意义的UI线程上的每一件事情源于活套,并在此线程excecution的所有路径会导致回吧!感谢Berdon企图回答我的问题,我确定我没有解释我的问题不够好:)


  

有关Android UI线程:在某些时候(可能是之前的任何
  活动等的创建)的框架内成立了一个活套
  (含的MessageQueue),并启动它。从这点上,
  一切,在UI线程上发生的情况是通过循环。本
  包括活动的生命周期管理等。所有你的回调
  倍率(的onCreate(),的onDestroy()...)至少indirecty
  从循环调度。可以看到,例如在堆栈
  异常的痕迹。 (你可以尝试一下,只写一个INT = 1/0;
  在OnCreate()中...)某处


I was wondering how the Looper class actually processes Runnables (via the Handler class) in the Thread that the Looper is attached to? If a looper is looping through its messageQueue then surely it would be a blocking operation for that thread? I imagine it itself must be performing some threading trickery but then how does it add the posted Runnables run() method onto the host threads stack?

Many questions! Any help would be much appreciated. Thanks!

EDIT:

Looking through the Looper class file class i see the below, which confuses me even more as all comments refer to the looper running in the main thread but also that its a blocking operation while waiting for new messages on the MessageQueue. How is this not blocking the UI / main thread???

    /**
     *  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());
    }

解决方案

Ok, looking around Stack I have found another question which answers mine. My main confusion was coming from a not realising the below from this post. I was incorrectly thinking of everything apart from the stuff posted to Handlers (and added to the Loopers MessageQueue) was being executed in a linear call stack, but thinking about it this is more likely how any program with a UI is implemented, and makes a lot more sense that every thing on the UI thread originated from the Looper and all paths of excecution on this thread will lead back to it! Thanks to Berdon for attempting to answer my question, im sure i didnt explain my issue well enough :)

Regarding the android UI thread: At some point (probably before any activities and the like are created) the framework has set up a Looper (containing a MessageQueue) and started it. From this point on, everything that happens on the UI thread is through that loop. This includes activity lifecycle management and so on. All callbacks you override (onCreate(), onDestroy()...) are at least indirecty dispatched from that loop. You can see that for example in the stack trace of an exception. (You can try it, just write int a = 1 / 0; somewhere in onCreate()...)

这篇关于Android的活套和调用堆栈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆