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

 更新时间:2016年11月12日 11:18:55   作者:屌丝迷途  
Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message 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。

相关文章

  • Android开发之自定义UI组件详解

    Android开发之自定义UI组件详解

    这篇文章主要给大家介绍了关于Android开发之自定义UI组件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • android使用FlipAnimation实现3D垂直翻转动画

    android使用FlipAnimation实现3D垂直翻转动画

    这篇文章主要为大家详细介绍了android使用FlipAnimation实现3D垂直翻转动画,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • 五分钟教你Android-Kotlin项目编写

    五分钟教你Android-Kotlin项目编写

    本篇文章主要介绍了五分钟教你Android-Kotlin项目编写,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Android Studio实现简易计算器

    Android Studio实现简易计算器

    这篇文章主要为大家详细介绍了Android Studio实现简易计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • Android View如何测量

    Android View如何测量

    这篇文章主要为大家介绍了Android View如何进行测量,本文为大家介绍view的测量方法,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • Android自定义processor实现bindView功能的实例

    Android自定义processor实现bindView功能的实例

    下面小编就为大家分享一篇Android自定义processor实现bindView功能的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Android中ArrayList和数组相互转换

    Android中ArrayList和数组相互转换

    在我们日常开发中难免会要将ArrayList和数组相互转换,那么如何才能相互转换呢?下面跟着小编一起通过这篇文章学习学习。
    2016-08-08
  • Android短信操作常见协议和常用代码

    Android短信操作常见协议和常用代码

    这篇文章主要介绍了Android短信操作常见协议和常用代码,本文直接给出代码实例,需要的朋友可以参考下
    2015-04-04
  • Android开发自学笔记(六):声明权限和Activity

    Android开发自学笔记(六):声明权限和Activity

    这篇文章主要介绍了Android开发自学笔记(六):声明权限和Activity,本文是上一篇的补充,需要的朋友可以参考下
    2015-04-04
  • android Chronometer控件使用大全

    android Chronometer控件使用大全

    Chronometer是一个简单的计时器,这篇文章主要介绍了android Chronometer控件简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09

最新评论