您现在的位置: 365建站网 > 365文章 > Android开发中Looper.prepare()和Looper.loop()

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

文章来源:365jz.com     点击数:329    更新时间:2017-08-14 15:37   参与评论

什么时候需要 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才会执行。

</>code

  1. class LooperThread extends Thread
  2. {
  3. 4 public void run()
  4. {
  5. Looper.prepare();
  6. //代码1....
  7. Looper.loop();
  8. //代码2....
  9. }
  10. }

警惕线程未终止造成的内存泄露;譬如在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源码

</>code

  1. public static final void main(String[] args) {
  2. ...
  3. //创建Looper和MessageQueue
  4. Looper.prepareMainLooper();
  5. ...
  6. //轮询器开始轮询
  7. Looper.loop();
  8. ...
  9. }

Looper.loop()方法

</>code

  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方法部分源码

</>code

  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。

 

如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛

您可能感兴趣的文章:

发表评论 (329人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
昵称:
最新评论
------分隔线----------------------------

快速入口

· 365软件
· 杰创官网
· 建站工具
· 网站大全

其它栏目

· 建站教程
· 365学习

业务咨询

· 技术支持
· 服务时间:9:00-18:00
365建站网二维码

Powered by 365建站网 RSS地图 HTML地图

copyright © 2013-2024 版权所有 鄂ICP备17013400号