A. android anr多长时间
broadcast超时时间为10秒
按键无响应的超时时间为5秒
service ANR超时的定义在ActiveServices.java中
前台service无响应的超时时间为20秒,后台service为200秒
B. Android如何避免ANR
ANR:Application Not Responding,五秒在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了: 对输入事件(如按键、触摸屏事件)的响应超过5秒 意向接受器(intentReceiver)超过10秒钟仍未执行完毕
Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。 因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。
C. 请教android service ANR问题
刚拿到anr的trace,还是无头绪,都是调用栈的mp,仔细看看,发现一个很好的信息隐藏在这个栈帧信息中:
如下一个栈帧:
----- pid 861 at 2012-02-11 14:57:50 -----
Cmd line: system_server
DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)
"main" prio=5 tid=1 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x2ba9c460 self=0x8e820
| sysTid=861 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=716342112
| schedstat=( 0 0 0 ) utm=464 stm=65 core=0
at com.android.server.am.ActivityManagerService.isUserAMonkey(ActivityManagerService.java:~6546)
- waiting to lock <0x2c1141c8> (a com.android.server.am.ActivityManagerService) held by tid=59 (Binder Thread #6)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:1273)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1545)
at android.os.Binder.execTransact(Binder.java:338)
at com.android.server.SystemServer.init1(Native Method)
at com.android.server.SystemServer.main(SystemServer.java:808)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
这说明什么?看上面的红色部分,说明这个主线程在等待锁一个object 0x2c1141c8 (通常就是synchronized操作,这里就是com.android.server.am.ActivityManagerService类型的一个object),但被tid=59占住了, 再看看 tid=59的栈帧:
"Binder Thread #6" prio=5 tid=59 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x2c3bd838 self=0x34c5d8
| sysTid=1120 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=3460688
| schedstat=( 0 0 0 ) utm=168 stm=48 core=0
at com.android.server.am.BatteryStatsService.noteStopWakelock(BatteryStatsService.java:~114)
- waiting to lock <0x2c117d50> (a com.android.internal.os.BatteryStatsImpl) held by tid=13 (ProcessStats)
at com.android.server.PowerManagerService.noteStopWakeLocked(PowerManagerService.java:798)
at com.android.server.PowerManagerService.releaseWakeLockLocked(PowerManagerService.java:1015)
at com.android.server.PowerManagerService.releaseWakeLock(PowerManagerService.java:967)
at android.os.PowerManager$WakeLock.release(PowerManager.java:319)
at android.os.PowerManager$WakeLock.release(PowerManager.java:300)
at com.android.server.am.ActivityStack.activityIdleInternal(ActivityStack.java:3254)
at com.android.server.am.ActivityManagerService.activityIdle(ActivityManagerService.java:3953)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:362)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1545)
at android.os.Binder.execTransact(Binder.java:338)
at dalvik.system.NativeStart.run(Native Method)
tid为何没有释放锁object 0x2c1141c8呢?因为它在等到锁 object 0x2c117d50(一个com.android.internal.os.BatteryStatsImpl类型的对象)!如果大家有较丰富的捉虫经验的话,看到这, 想必都清楚了,持锁时又请求锁,极大的可能就是死锁了!
再看请求的锁被tid=13持有的情况吧:
"ProcessStats" prio=5 tid=13 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x2c146f58 self=0x2954f0
| sysTid=877 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=2709096
| schedstat=( 0 0 0 ) utm=6 stm=4 core=0
at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:~12430)
- waiting to lock <0x2c1141c8> (a com.android.server.am.ActivityManagerService) held by tid=59 (Binder Thread #6)
at android.app.ContextImpl.sendBroadcast(ContextImpl.java:909)
at com.android.server.DropBoxManagerService.add(DropBoxManagerService.java:236)
at android.os.DropBoxManager.addText(DropBoxManager.java:272)
at com.android.server.am.ActivityManagerService$11.run(ActivityManagerService.java:7630)
at com.android.server.am.ActivityManagerService.addErrorToDropBox(ActivityManagerService.java:7635)
at com.android.server.am.ActivityManagerService.handleApplicationWtf(ActivityManagerService.java:7448)
at com.android.internal.os.RuntimeInit.wtf(RuntimeInit.java:345)
at android.util.Log$1.onTerribleFailure(Log.java:103)
at android.util.Log.wtf(Log.java:278)
at com.android.internal.os.BatteryStatsImpl.(BatteryStatsImpl.java:5738)
at com.android.internal.os.BatteryStatsImpl.access$100(BatteryStatsImpl.java:76)
at com.android.internal.os.BatteryStatsImpl$Uid.(BatteryStatsImpl.java:2457)
at com.android.internal.os.BatteryStatsImpl$Uid.getTcpBytesReceived(BatteryStatsImpl.java:2446)
at com.android.internal.os.BatteryStatsImpl.writeSummaryToParcel(BatteryStatsImpl.java:5437)
at com.android.internal.os.BatteryStatsImpl.writeLocked(BatteryStatsImpl.java:4836)
at com.android.internal.os.BatteryStatsImpl.writeAsyncLocked(BatteryStatsImpl.java:4818)
at com.android.server.am.ActivityManagerService.updateCpuStatsNow(ActivityManagerService.java:1649)
at com.android.server.am.ActivityManagerService$3.run(ActivityManagerService.java:1531)
D. Android ANR 机制
广播的 ANR 处理相对简单,主要是再次判断是否超时、记录日志,记录 ANR 次数等。然后就继续调用 processNextBroadcast 函数,处理下一条广播了。
ContentProvider 超时为 CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s
Activity 的 ANR 是相对最复杂的,也只有 Activity 中出现的 ANR 会弹出 ANR 提示框。
最终的表现形式是:弹出一个对话框,告诉用户当前某个程序无响应,输入一大堆与 ANR 相关的日志,便于开发者解决问题。
InputDispatching:
Activity 最主要的功能之一是交互,为了方便交互,Android 中的 InputDispatcher 会发出操作事件,最终在 InputManagerService 中发出事件,通过 InputChannel,向 Activity 分发事件。交互事件必须得到响应,如果不能及时处理,IMS 就会报出 ANR,交给 AMS 去弹出 ANR 提示框。
KeyDispatching:
如果输入是个 Key 事件,会从 IMS 进入 ActivityRecord.Token.keyDispatchingTimeOut,然后进入 AMS 处理,不同的是,在 ActivityRecord 中,会先截留一次 Key 的不响应,只有当 Key 连续第二次处理超时,才会弹出 ANR 提示框。
窗口焦点:
Activity 总是需要有一个当前窗口来响应事件的,但如果迟迟没有当前窗口(获得焦点),比如在 Activity 切换时,旧 Activity 已经 onPause,新的 Activity 一直没有 onResume,持续超过 5 秒,就会 ANR。
App 的生命周期太慢,或 CPU 资源不足,或 WMS 异常,都可能导致窗口焦点。
1. 判断是否有 focused 组件以及 focused Application:
这种一般是在应用启动时触发,比如启动时间过长在这过程中触发了 keyevent 或者 trackball moteionevent 就会出现。
对应于
2. 判断前面的事件是否及时完成:
对应于
出现这种问题意味着主线程正在执行其他的事件但是比较耗时导致输入事件无法及时处理。
InputDispatcher 超时是最常见的 ANR 类型,而且其类型也比较多。
当用户触摸屏幕或者按键操作,首次触发的是硬件驱动,驱动收到事件后,将该相应事件写入到输入设备节点, 这便产生了最原生态的内核事件。接着,输入系统取出原生态的事件,经过层层封装后成为 KeyEvent 或者 MotionEvent ;最后,交付给相应的目标窗口(Window)来消费该输入事件。可见,输入系统在整个过程起到承上启下的衔接作用。
Input 模块的主要组成:
每一个应用进程都会有一个 SignalCatcher 线程,专门处理 SIGQUIT,来到 art/runtime/signal_catcher.cc :
当应用发生 ANR 之后,系统会收集许多进程,来 mp 堆栈,从而生成 ANR Trace 文件。收集的第一个,也是一定会被收集到的进程,就是发生 ANR 的进程。接着系统开始向这些应用进程发送 SIGQUIT 信号,应用进程收到 SIGQUIT 后开始 mp 堆栈。
[1] developer ANRs
[2] Android ANR 分析详解
[3] 看完这篇 Android ANR 分析,就可以和面试官装逼了!
[4] 微信 Android 团队手把手教你高效监控 ANR
[5] Input 系统—ANR 原理分析 - Gityuan
[6] 彻底理解安卓应用无响应机制 - Gityuan
[7] 理解 Android ANR 的触发原理 - Gityuan
E. android activity 中的 service 方法是否异步执行拜托各位大神
异步执行
android中,activity、service都是在主线程,service与activity的主要区别就是service没有前台界面,不能直接与用户交互,另外可以相对保证不会被系统随便的kill掉。所以service适用于一些无需交互的后台操作,但如果你直接在service中进行耗时操作的话,因为在主线程所以依然会出现和activity主线程一样的超时的问题,所以好的方式是在service中启动其他的线程去执行耗时操作。
F. 请教android service ANR问题
ANR(ApplicationNotResponding)ANR定义:在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:ApplicationNotResponding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。所以一个流畅的合理的应用程序中不能出现anr,而让用户每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样系统不会显示ANR给用户。默认情况下,在android中Activity的最长执行时间是5秒,BroadcastReceiver的最长执行时间则是10秒。第一:什么会引发ANR?在Android里,应用程序的响应性是由ActivityManager和WindowManager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)2.BroadcastReceiver在10秒内没有执行完毕造成以上两点的原因有很多,比如在主线程中做了非常耗时的操作,比如说是下载,io异常等。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。然而,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用Thread.wait()或是Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。第二:如何避免ANR?1、运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。(可以采用重新开启子线程的方式,然后使用Handler+Message的方式做一些操作,比如更新主线程中的ui等)2、应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个Service。(此处需要注意的是可以在广播接受者中启动Service,但是却不可以在Service中启动broadcasereciver,关于原因后续会有介绍,此处不是本文重点)3、避免在IntentReceiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广播时需要向用户展示什么,你应该使用NotificationManager来实现。总结:anr异常也是在程序中自己经常遇到的问题,主要的解决法自己最常用的就是不要在主线程中做耗时的操作,而应放在子线程中来实现,比如采用Handler+mesage的方式,或者是有时候需要做一些和网络相互交互的耗时操作就采用asyntask异步任务的方式(它的底层其实Handler+mesage有所区别的是它是线程池)等,在主线程中更新UI。
G. 如何分析解决Android ANR
Android ANR是程序无法响应的问题,可以由以下方式解决:
将一些消耗时间的代码放到Handler类里面去执行,相当于另外开一个线程,不会阻塞主线程,从而避免引发ANR的问题,如下代码:
private Handler handler = new Handler(); //新建一个handler类
private Runnable myRunnable= new Runnable() { //新建一个Runnable来开设一个线程
public void run() {
if (run) {
handler.postDelayed(this, 1000);
count++;
}
tvCounter.setText("Count: " + count); //里面来执行一些控件的更新
}
};
应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为 BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个 Service。
H. 安卓开发ANR怎么处理
原因分析:android系统中处理用户操作的工作时在主线程中执行的,如果我们的程序在主线程中进行一些耗时的操作,导致用户的操作6秒不能够处理,就会出现异常。
主线程休眠,那么再点击程序,必须等主线程睡醒后才会反应。
所以在主线程中不要做太耗时的工作,因为主界面会阻塞。
解决办法:让这些耗时的操作放在新线程里面操作。
注意:如果新线程里面做的事情要更新界面的话,就要使用handler来操作。
连接网络的事都要放在新线程里面的。
解决代码(包括更新界面的操作,使用的是handler):
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private TextView numTV;
private Handler handler = new Handler();
private int i;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
numTV = (TextView) findViewById(R.id.numTV);
}
public void doSomething(View view) throws Exception {
new Thread() {
public void run() {
for (i = 1; i < 20; i++) {
handler.post(new Runnable() {
public void run() {
numTV.setText(i + "");
}
});
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
public void toast(View view) {
Toast.makeText(this, "十八大开幕了!", 0).show();
}
}