为什么在主线程的Looper.looper死循环不会卡死
2016-05-30 17:40
483 查看
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()里面处理耗时操作,那么下一次的比如用户的点击事件不能处理了,那就会卡死了
相关文章推荐
- hadoop pipes 中遇到问题
- centos6.5 下安装gcc4.8.2
- LINUX 对引导加密
- Nginx作为反向代理时传递客户端IP的设置方法
- 网站收藏
- windows下使用openssl的一种方法
- nginx配置防盗链
- 在CentOS下源码安装 Xen并搭建Windows虚拟机
- 初识nginx
- log4j.properties配置
- log4j.properties配置
- 【Linux】Linux系统下find指令详细用法与示例
- 【Linux】LINUX操作系统下VIM的安装和配置
- maven学习(2):常用命令及tomcat插件和jetty插件部署
- Linux 命令修改系统时间
- 在linux环境下尝试使用gcc编译一个程序,并验证-E\-S\-c选项
- Linux用户和组相关的配置文件
- linux基础命令之sed
- redhat linux安装jdk1.8
- 简单Git服务器搭建