ANR(应用程序无响应)-应用程序无响应时发生的错误。 结果,将打开一个对话框,提示用户等待或关闭应用程序。

ANR条件
- 输入事件(按钮和触摸事件)在5秒钟内未处理;
- 在指定的时间内(前景-10 s,背景-60 s)未处理BroadcastReceiver(onRecieve());
- ContentProvider在10秒内未完成。
通常,主线程被阻塞。
如果您阅读了我的文章,您可能已经习惯了我们抓取源代码的事实。 因此,让我们看看
ANR在引擎盖下的外观。
AppErrors类不仅
处理 ANR,还
处理应用程序中可能发生的其他错误,包括崩溃。 handleShowAnrUi()方法只是为显示ANR的许多开发人员和用户打开了这个可怕的窗口。
class AppErrors { ... void handleShowAnrUi(Message msg) { Dialog dialogToShow = null; synchronized (mService) { AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj; final ProcessRecord proc = data.proc; if (proc == null) { Slog.e(TAG, "handleShowAnrUi: proc is null"); return; } if (proc.anrDialog != null) { Slog.e(TAG, "App already has anr dialog: " + proc); MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.ALREADY_SHOWING); return; } Intent intent = new Intent("android.intent.action.ANR"); if (!mService.mProcessesReady) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); } mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, 0 ); boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; if (mService.canShowErrorDialogs() || showBackground) { dialogToShow = new AppNotRespondingDialog(mService, mContext, data); proc.anrDialog = dialogToShow; } else { MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.CANT_SHOW);
但是,ANR并非从此处开始。 就像我上面说的那样,此错误的首要原因之一是输入事件的延迟,即5秒。 通过简短搜索,我们可以找到该值的设置位置。
namespace android {
现在我们可以查看调用本机部分的代码。 这发生在类
InputManagerService中 。
这是InputMonitor中的
mWindowManagerCallbacks :
if (appWindowToken != null && appWindowToken.appToken != null) {
让我们仔细看一下inputDispatchingTimedOut()。 在这里,我们只是通过ActivityManager显示有关超时到期的消息,并让用户决定是取消操作还是继续等待。 在崩溃或ANR的情况下,正是在
ActivityManagerService中调用AppErrors。
private boolean makeAppCrashingLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace) { app.crashing = true; app.crashingReport = generateProcessError(app, ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace); startAppProblemLocked(app); app.stopFreezingAllLocked(); return handleAppCrashLocked(app, shortMsg, longMsg, stackTrace); } private void makeAppNotRespondingLocked(ProcessRecord app, String activity, String shortMsg, String longMsg) { app.notResponding = true; app.notRespondingReport = generateProcessError(app, ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, activity, shortMsg, longMsg, null); startAppProblemLocked(app); app.stopFreezingAllLocked(); }
ANR的主要原因
- 输入/输出锁定
- 网络拥塞
- 线程阻塞
- 无休止的循环
- 业务逻辑花费的时间太长
避免ANR
- 主用户界面线程执行仅与用户界面相关联的逻辑。
- 复杂的计算(例如,数据库操作,输入输出操作,网络操作等)在单独的流中执行;
- 使用处理程序在用户界面线程和工作流之间进行交互;
- 使用RxJava等 处理异步操作。
如何捕捉ANR
PS我在电报频道
@paradisecurity中发布了所有选择。