为什么在主线程的Looper.looper死循环不会卡死

原创 2016年05月30日 17:40:01
public static void main(String[] args) { 
.... //创建Looper和MessageQueue对象,用于处理主线程的消息 
Looper.prepareMainLooper();
 //创建ActivityThread对象 
//建立Binder通道 (创建新线程) 
thread.attach(false); Looper.loop(); //消息循环运行 
throw new RuntimeException("Main thread loop unexpectedly exited");
 }

我们看looper.loop()的源码


    /** 
         * Run the message queue in this thread. Be sure to call 
         * {@link #quit()} to end the loop. 
         */  
        public static void loop() {  
            Looper me = myLooper();//获取当前looper  
            if (me == null) {  
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
            }//如果为空,则抛异常  
            MessageQueue queue = me.mQueue;//把当前looper的queue赋值给局部变量queue  

            // 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();//确保当前线程属于当前进程,并且记录真实的token。  
            final long ident = Binder.clearCallingIdentity();  

            while (true) {  
                Message msg = queue.next(); // might block有可能会阻塞  
                if (msg != null) {  
                    if (msg.target == null) {  
                        // No target is a magic identifier for the quit message.退出消息的标示就是target为空  
                        return;  
                    }  

                    long wallStart = 0;  
                    long threadStart = 0;  

                    // This must be in a local variable, in case a UI event sets the logger 一个局部变量,为ui事件设置log记录。  
                    Printer logging = me.mLogging;  
                    if (logging != null) {  
                        logging.println(">>>>> Dispatching to " + msg.target + " " +  
                                msg.callback + ": " + msg.what);  
                        wallStart = SystemClock.currentTimeMicro();  
                        threadStart = SystemClock.currentThreadTimeMicro();  
                    }  
                     //handler处理消息  
                    msg.target.dispatchMessage(msg);  

                    if (logging != null) {  
                        long wallTime = SystemClock.currentTimeMicro() - wallStart;  
                        long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;  

                        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
                        if (logging instanceof Profiler) {  
                            ((Profiler) logging).profile(msg, wallStart, wallTime,  
                                    threadStart, threadTime);  
                        }  
                    }  

                    // 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(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);  
                    }  
                    //处理完成后,调用Message.recycle()将其放入Message Pool中。
                    msg.recycle();  
                }  
            }  
        }  

那么知乎上一个大神这么说 隔开隔开

对于线程既然是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程退出。而对于主线程,我们是绝不希望会被运行一段时间,自己就退出,那么如何保证能一直存活呢?简单做法就是可执行代码是能一直执行下去的,死循环便能保证不会被退出,例如,binder线程也是采用死循环的方法,通过循环方式不同与Binder驱动进行读写操作,当然并非简单地死循环,无消息时会休眠。但这里可能又引发了另一个问题,既然是死循环又如何去处理其他事务呢?通过创建新线程的方式。
真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。

作者:Gityuan
链接:https://www.zhihu.com/question/34652589/answer/90344494
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

隔开隔开
这是一个大神说的 乍看起来好像有点不懂
那么我来说说我的理解
Looper.loop()中的for循环会让当前线程阻塞,不是卡死,这个和操作系统有关。如果你在主线程操作,如activity生命周期onCreate、主线程的handler,实际上是都是通过handler发消息的,消息会在刚才的for循环中处理,这个消息会唤醒线程,如果你在onCreate(),onResume()里面处理耗时操作,那么下一次的比如用户的点击事件不能处理了,那就会卡死了

Android中为什么主线程不会因为Looper.loop()方法造成阻塞

Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
  • u013435893
  • u013435893
  • 2016年03月16日 10:47
  • 6452

【Android自助餐】Handler消息机制完全解析(四)Looper解析

Android自助餐Handler消息机制完全解析(四)Looper解析Android自助餐Handler消息机制完全解析四Looper解析 Looper 初始化prepare 提供looper获取接...
  • xmh19936688
  • xmh19936688
  • 2016年07月13日 20:53
  • 8643

Looper、Handler在子线程中的应用

Looper类:为一个线程开启一个消息循环,里面有一个消息队列,新线程是没有开启消息循环的,所以需要用到Looper的方法创建消息循环(主线程除外,主线程会自动为其创建Looper对象,开启消息循环)...
  • namePeng
  • namePeng
  • 2016年04月28日 16:45
  • 1195

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

 Android中为什么主线程不会因为Looper.loop()里的死循环卡死? app程序入口中为主线程准备好了消息队列 … 显示全部   分享   ...
  • tiandiren2007
  • tiandiren2007
  • 2016年03月12日 21:07
  • 3438

Android如何保证一个线程最多只能有一个Looper?

Thread-Specific Storage Pattern
  • sun927
  • sun927
  • 2016年04月01日 21:04
  • 4732

Android 线程 Looper.prepare()、Looper.loop()

Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建一个消息循环,调用Loope...
  • heng615975867
  • heng615975867
  • 2013年06月28日 10:09
  • 5771

主线程为何不会因为Looper.loop()方法阻塞

http://blog.csdn.net/u013435893/article/details/50903082
  • bbye913
  • bbye913
  • 2017年09月19日 22:49
  • 138

关于主线程中自动建立的Looper的思考:主线程中Looper中的轮询死循环为何没有阻塞主线程

Android中UI线程会自动给我们建立一个looper,但是looper中的loop方法是个死循环.为什么我们在UI线程中写的代码为何都能顺利执行?为什么没有引起ANR呢? Looper的部分源码...
  • u012045061
  • u012045061
  • 2016年02月08日 12:32
  • 1731

Android面试:主线程中的Looper.loop()一直无限循环为什么不会造成ANR?(转)

引子:正如我们所知,在android中如果主线程中进行耗时操作会引发ANR(Application Not Responding)异常。造成ANR的原因一般有两种: 当前的事件没有机会得到处理(...
  • zjf1165
  • zjf1165
  • 2016年08月15日 12:41
  • 3219

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

问题来源: app程序入口中为主线程准备好了消息队列 而根据Looper.loop()源码可知里面是一个死循环在遍历消息队列取消息 而且并也没看见哪里有相关代码为...
  • xhmj12
  • xhmj12
  • 2016年09月13日 10:25
  • 1093
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:为什么在主线程的Looper.looper死循环不会卡死
举报原因:
原因补充:

(最多只允许输入30个字)