有过Android开发经历的人都不会对ANR陌生,它和崩溃一样是程序设计的问题。本文将以较为深入的视角来介绍什么是ANR,出现场景,如何避免以及如何定位分析ANR,希望可以帮助大家在编写程序时有所帮助。

什么是ANR

ANR全称Application Not Responding,意思就是程序未响应。如果一个应用无法响应用户的输入,系统就会弹出一个ANR对话框,如下图所示,用户可以自行选择继续等待亦或者是停止当前程序。

出现场景

  • 主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。
  • 主线程中存在耗时的计算
  • 主线程中错误的操作,比如Thread.wait或者Thread.sleep等

Android系统会监控程序的响应状况,一旦出现下面两种情况,则弹出ANR对话框

  • 应用在5秒内未响应用户的输入事件(如按键或者触摸)
  • BroadcastReceiver未在10秒内完成相关的处理

如何避免

基本的思路就是将IO操作在工作线程来处理,减少其他耗时操作和错误操作

  • 使用AsyncTask处理耗时IO操作。
  • 使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
  • 使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
  • Activity的onCreate和onResume回调中尽量避免耗时的代码
  • BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。

画龙点睛

通常100到200毫秒就会让人察觉程序反应慢,为了更加提升响应,可以使用下面的几种方法

  • 如果程序正在后台处理用户的输入,建议使用让用户得知进度,比如使用ProgressBar控件。
  • 程序启动时可以选择加上欢迎界面,避免让用户察觉卡顿。
  • 使用Systrace和TraceView找出影响响应的问题。

如何定位

如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt即可,最新的ANR信息在最开始部分。我们从stacktrace中即可找到出问题的具体行数。本例中问题出现在MainActivity.java 27行,因为这里调用了Thread.sleep方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@htc_m8tl:/ # cat /data/anr/traces.txt | more

----- pid 30307 at 2015-05-30 14:51:14 -----
Cmd line: com.example.androidyue.bitmapdemo

JNI: CheckJNI is off; workarounds are off; pins=0; globals=272

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

"main" prio=5 tid=1 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 obj=0x416eaf18 self=0x416d8650
  | sysTid=30307 nice=0 sched=0/0 cgrp=apps handle=1074565528
  | state=S schedstat=( 0 0 0 ) utm=5 stm=4 core=3
  at java.lang.VMThread.sleep(Native Method)
  at java.lang.Thread.sleep(Thread.java:1044)
  at java.lang.Thread.sleep(Thread.java:1026)
  at com.example.androidyue.bitmapdemo.MainActivity$1.run(MainActivity.java:27)
  at android.app.Activity.runOnUiThread(Activity.java:4794)
  at com.example.androidyue.bitmapdemo.MainActivity.onResume(MainActivity.java:33)
  at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1282)
  at android.app.Activity.performResume(Activity.java:5405)

如果是线上版本引起的,Google Play后台有相关的数据可以帮助查看分析并解决问题。

细致分析

提问: BroadcastReceiver过了60秒居然没有ANR? 现场代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class NetworkReceiver extends BroadcastReceiver{
    private static final String LOGTAG = "NetworkReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(LOGTAG, "onReceive intent=" + intent);
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.i(LOGTAG, "onReceive end");
    }
}

回答:实际上已经发生了ANR,只是没有进行对话框弹出而已。这种ANR就是background ANR,即后台程序的ANR,我们可以通过过滤日志验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
adb logcat | grep "NetworkReceiver|ActivityManager|WindowManager"
I/NetworkReceiver( 4109): onReceive intent=Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x8000010 cmp=com.example.androidyue.bitmapdemo/.NetworkReceiver (has extras) }
I/ActivityManager(  462): No longer want com.android.exchange (pid 1054): empty #17
I/NetworkReceiver( 4109): onReceive end
W/BroadcastQueue(  462): Receiver during timeout: ResolveInfo{5342dde4 com.example.androidyue.bitmapdemo.NetworkReceiver p=0 o=0 m=0x108000}
E/ActivityManager(  462): ANR in com.example.androidyue.bitmapdemo
E/ActivityManager(  462): Reason: Broadcast of Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x8000010 cmp=com.example.androidyue.bitmapdemo/.NetworkReceiver (has extras) }
E/ActivityManager(  462): Load: 0.37 / 0.2 / 0.14
E/ActivityManager(  462): CPU usage from 26047ms to 0ms ago:
E/ActivityManager(  462):   0.4% 58/adbd: 0% user + 0.4% kernel / faults: 1501 minor
E/ActivityManager(  462):   0.3% 462/system_server: 0.1% user + 0.1% kernel
E/ActivityManager(  462):   0% 4109/com.example.androidyue.bitmapdemo: 0% user + 0% kernel / faults: 6 minor
E/ActivityManager(  462): 1.5% TOTAL: 0.5% user + 0.9% kernel + 0% softirq
E/ActivityManager(  462): CPU usage from 87ms to 589ms later:
E/ActivityManager(  462):   1.8% 58/adbd: 0% user + 1.8% kernel / faults: 30 minor
E/ActivityManager(  462):     1.8% 58/adbd: 0% user + 1.8% kernel
E/ActivityManager(  462): 4% TOTAL: 0% user + 4% kernel
W/ActivityManager(  462): Killing ProcessRecord{5326d418 4109:com.example.androidyue.bitmapdemo/u0a10063}: background ANR
I/ActivityManager(  462): Process com.example.androidyue.bitmapdemo (pid 4109) has died.

除了日志,我们还可以根据前面提到的查看traces.txt文件。

提问:可以更容易了解background ANR么?

回答:当然可以,在Android开发者选项—>高级—>显示所有”应用程序无响应“勾选即可对后台ANR也进行弹窗显示,方便查看了解程序运行情况。

Android中的ANR的更多相关文章

  1. Android中的ANR问题

    ANR:(Application Not Responding) 1.为什么会产生ANR 在Android中App的相应能力是由Activity Manager和Window Manager系统服务来 ...

  2. Android开发中的ANR问题如何避免?

    在Android中, Activity Manager 和 Window Manager system services 会监控每个程序的运行,当程序出现如下三种种情况的时候就会弹出ANR的提示对话框 ...

  3. URL转Drawable之 Android中获取网络图片的三种方法

    转载自: http://doinone.iteye.com/blog/1074283 Android中获取网络图片是一件耗时的操作,如果直接获取有可能会出现应用程序无响应(ANR:Applicatio ...

  4. Android中的Touch事件

    Android中的Touch事件处理 主要内容 Activity或View类的onTouchEvent()回调函数会接收到touch事件. 一个完整的手势是从ACTION_DOWN开始,到ACTION ...

  5. Android 系统稳定性 - ANR(二)(转)

    编写者:李文栋P.S. OpenOffice粘贴过来后格式有些混乱. 1.2 如何分析ANR问题 引起ANR问题的根本原因,总的来说可以归纳为两类: 应用进程自身引起的,例如: 主线程阻塞.挂起.死循 ...

  6. Android中对Log日志文件的分析[转]

    一,Bug出现了, 需要“干掉”它 bug一听挺吓人的,但是只要你懂了,android里的bug是很好解决的,因为android里提供了LOG机制,具体的底层代码,以后在来分析,只要你会看bug, a ...

  7. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

  8. Android中进程与线程

    常说的主线程(UI线程)是什么? 当一个Android程序刚启动的时候,我们的android系统就会启动一个带有一个单一线程的linux进程.默认情况下,所有的组件比如Activity都运行在同样的一 ...

  9. android中的一些问题

    1. Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚 ...

随机推荐

  1. AOJ DSL_2_E Range Add Query (RAQ)

    Range Add Query 数列 A = {a1,a2,...,an} に対し.次の2つの操作を行うプログラムを作成せよ. add(s,t,x): as,as+1,...,at にxを加算する. ...

  2. java获取当天,前天,明天,本周,本月,本年的开始日期时间和结束日期时间

    package demoone; import java.sql.Timestamp; import java.text.ParseException; import java.text.Simple ...

  3. 自然语言25_nltk.book

    测试NLTK数据包 导入nltk.book包中所有的东西: 能使用以下函数的是nltk.text.Text对象 from nltk.book import * text1.concordance(&q ...

  4. EmguCV(OpenCV)实现高效显示视频(YUV)叠加包括汉字

    视频处理中,往往需要在上面增加文字包括汉字英文字母数字标点等,Emgu.CV/opencv 绘图 线面文字包括中文 这篇里也有相关介绍,但是这篇里根据逐像素修改rgb值的方法效率太低 查了很多资料,基 ...

  5. AE套宗获取内环

    主要根据IPolygon4的get_InteriorRingBag方法. IGeometry geo = null; IRing exring = null; (geo as IPolygon2).Q ...

  6. Extjs 学习总结-Ext.define自定义类

    本教程整理了extjs的一些基本概念及其使用,包括自定义类(Ext.define).数据模型.代理等.本节介绍使用Ext.define自定义类 使用Ext.define自定义类 1. 首先看看js中自 ...

  7. 设置arc 的默认编辑器

    arc set-config editor "vim" 转自:http://udn.yyuap.com/thread-39791-1-1.html Pharicator是FB的代码 ...

  8. ThinkPHP3.2.3整合smarty模板(二)

    前言:继ThinkPHP3.2.3整合smarty模板(一)之后,继续来探讨一下tp框架整合smarty模板,看到有人在群上问到怎么使用自定义的常量,今天就具体来谈谈: 一.开发一个项目,必不可少会用 ...

  9. 利用Render Texture实现游戏的小雷达效果(摄影机分屏)

    最近游戏蛮牛在举办一个活动,就是要做出这样的效果: 题目:实现游戏分屏效果 要求:1.        分屏,且分割线不规则(即非水平或垂直):2.        各屏可单独操作(移动.缩放),操作指该 ...

  10. hive单机安装(实战)

    hive使用与注意事项:http://blog.csdn.net/stark_summer/article/details/44222089 连接命令:beeline -n root -u jdbc: ...