欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发中Looper.prepare()和Looper.loop()

程序员文章站 2024-03-01 09:45:52
什么时候需要 looper   looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用loope...

什么时候需要 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。