Android开发中Looper.prepare()和Looper.loop()
什么时候需要 looper
looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用looper.prepare()来给线程创建一个消息循环,调用looper.loop()来使消息循环起作用,使用looper.prepare()和looper.loop()创建了消息队列就可以让消息处理在该线程中完成。
使用looper需要注意什么
写在looper.loop()之后的代码不会被立即执行,当调用后mhandler.getlooper().quit()后,loop才会中止,其后的代码才能得以运行。looper对象通过messagequeue来存放消息和事件。一个线程只能有一个looper,对应一个messagequeue。
比如下面的代码,只要调用了getlooper().quit()后代码2才会执行。
class looperthread extends thread { 4 public void run() { looper.prepare(); //代码1.... looper.loop(); //代码2.... } }
警惕线程未终止造成的内存泄露;譬如在activity中关联了一个生命周期超过activity的thread,在退出activity时切记结束线程。一个典型的例子就是handlerthread的run方法是一个死循环,它不会自己结束,线程的生命周期超过了activity生命周期,我们必须手动在activity的销毁方法中中调运thread.getlooper().quit();才不会泄露。
looper与activity
activity的mainui线程默认是有消息队列的。所以在activity中新建handler时,不需要先调用looper.prepare()
主线程中的looper.loop()一直无限循环为什么不会造成anr
activitythread.java 是主线程入口的类,这里你可以看到写java程序中司空见惯的main方法,而main方法正是整个java程序的入口。
activitythread源码
public static final void main(string[] args) { ... //创建looper和messagequeue looper.preparemainlooper(); ... //轮询器开始轮询 looper.loop(); ... }
looper.loop()方法
while (true) { //取出消息队列的消息,可能会阻塞 message msg = queue.next(); // might block ... //解析消息,分发消息 msg.target.dispatchmessage(msg); ... }
activitythread的main方法主要就是做消息循环,一旦退出消息循环,那么你的应用也就退出了。那为什么这个死循环不会造成anr异常呢?
因为android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说activity的生命周期都是运行在 looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 looper.loop(),而不是 looper.loop() 阻塞它。也就说我们的代码其实就是在这个循环里面去执行的,当然不会阻塞了。
handlemessage方法部分源码
public void handlemessage(message msg) { if (debug_messages) slog.v(tag, ">>> handling: " + codetostring(msg.what)); switch (msg.what) { case launch_activity: { trace.tracebegin(trace.trace_tag_activity_manager, "activitystart"); final activityclientrecord r = (activityclientrecord) msg.obj; r.packageinfo = getpackageinfonocheck(r.activityinfo.applicationinfo, r.compatinfo); handlelaunchactivity(r, null); trace.traceend(trace.trace_tag_activity_manager); } break; case relaunch_activity: { trace.tracebegin(trace.trace_tag_activity_manager, "activityrestart"); activityclientrecord r = (activityclientrecord) msg.obj; handlerelaunchactivity(r); trace.traceend(trace.trace_tag_activity_manager); } break; case pause_activity: trace.tracebegin(trace.trace_tag_activity_manager, "activitypause"); handlepauseactivity((ibinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0); maybesnapshot(); trace.traceend(trace.trace_tag_activity_manager); break; case pause_activity_finishing: trace.tracebegin(trace.trace_tag_activity_manager, "activitypause"); handlepauseactivity((ibinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0); trace.traceend(trace.trace_tag_activity_manager); break; ........... } }
可以看见activity的生命周期都是依靠主线程的looper.loop,当收到不同message时则采用相应措施。
如果某个消息处理时间过长,比如你在oncreate(),onresume()里面处理耗时操作,那么下一次的消息比如用户的点击事件不能处理了,整个循环就会产生卡顿,时间一长就成了anr。
上一篇: asp.net Textbox服务器控件
下一篇: 详解Spring全局异常处理的三种方式
推荐阅读
-
Android开发中Looper.prepare()和Looper.loop()
-
Android应用开发中WebView的常用方法笔记整理
-
Android开发中类加载器DexClassLoader的简单使用讲解
-
Android开发apk反编译和二次打包教程
-
Android开发中实现IOS风格底部选择器(支持时间 日期 自定义)
-
Android开发之ListView的head消失页面导航栏的渐变出现和隐藏
-
Android App开发中创建Fragment组件的教程
-
Android App开发中自定义View和ViewGroup的实例教程
-
Android中invalidate()和postInvalidate() 的区别及使用方法
-
Android开发中Dialog半透明背景消失