Looper.prepare()和Looper.loop()
Posted 屌丝迷途
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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才会执行。
1 class LooperThread extends Thread 2 { 3 4 public void run() 5 { 6 Looper.prepare(); 7 //代码1.... 8 Looper.loop(); 9 //代码2.... 10 } 11 }
警惕线程未终止造成的内存泄露;譬如在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源码
1 public static final void main(String[] args) { 2 ... 3 //创建Looper和MessageQueue 4 Looper.prepareMainLooper(); 5 ... 6 //轮询器开始轮询 7 Looper.loop(); 8 ... 9 }
Looper.loop()方法
1 while (true) { 2 //取出消息队列的消息,可能会阻塞 3 Message msg = queue.next(); // might block 4 ... 5 //解析消息,分发消息 6 msg.target.dispatchMessage(msg); 7 ... 8 }
ActivityThread的main方法主要就是做消息循环,一旦退出消息循环,那么你的应用也就退出了。那为什么这个死循环不会造成ANR异常呢?
因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。也就说我们的代码其实就是在这个循环里面去执行的,当然不会阻塞了。
handleMessage方法部分源码
1 public void handleMessage(Message msg) { 2 if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); 3 switch (msg.what) { 4 case LAUNCH_ACTIVITY: { 5 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 6 final ActivityClientRecord r = (ActivityClientRecord) msg.obj; 7 r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo); 8 handleLaunchActivity(r, null); 9 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 10 } 11 break; 12 case RELAUNCH_ACTIVITY: { 13 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart"); 14 ActivityClientRecord r = (ActivityClientRecord) msg.obj; 15 handleRelaunchActivity(r); 16 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 17 } 18 break; 19 case PAUSE_ACTIVITY: 20 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); 21 handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0); 22 maybeSnapshot(); 23 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 24 break; 25 case PAUSE_ACTIVITY_FINISHING: 26 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); 27 handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0); 28 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 29 break; 30 ........... 31 } 32 }
可以看见Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施。
如果某个消息处理时间过长,比如你在onCreate(),onResume()里面处理耗时操作,那么下一次的消息比如用户的点击事件不能处理了,整个循环就会产生卡顿,时间一长就成了ANR。
以上是关于Looper.prepare()和Looper.loop()的主要内容,如果未能解决你的问题,请参考以下文章
调用 Handler 时是不是需要调用 Looper.prepare()
无法在 aynctask 中未调用 Looper.prepare() 异常的线程内创建处理程序
android错误“无法在未调用looper.prepare的线程内创建处理程序” [重复]
CountDownTimer:“无法在未调用 Looper.prepare() 的线程内创建处理程序”