ANR (Application Not Responding) - Une erreur qui se produit lorsque l'application ne répond pas. Par conséquent, une boîte de dialogue s'ouvre invitant l'utilisateur à attendre ou à fermer l'application.

Conditions ANR
- Les événements d'entrée (boutons et événements tactiles) ne sont pas traités pendant 5 secondes;
- BroadcastReceiver (onRecieve ()) n'a pas été traité dans le délai spécifié (premier plan - 10 s, arrière-plan - 60 s);
- ContentProvider n'est pas terminé dans les 10 secondes.
Habituellement, le thread principal est bloqué.
Si vous lisez mes articles, vous êtes probablement déjà habitué au fait que nous explorons le code source. Voyons donc à quoi ressemble l'
ANR sous le capot .
La classe
AppErrors gère non seulement l'ANR, mais également d'autres erreurs qui peuvent se produire dans l'application, y compris un crash. La méthode handleShowAnrUi () ouvre juste cette fenêtre effrayante pour de nombreux développeurs et utilisateurs qui affiche 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);
Cependant, l'ANR ne démarre pas ici. Comme je l'ai dit ci-dessus, l'une des premières causes de cette erreur est le retard de l'événement d'entrée, qui est de 5 secondes. Par une courte recherche, nous pouvons trouver où cette valeur est définie.
namespace android {
Maintenant, nous pouvons regarder dans le code où la partie native est appelée. Cela se produit dans la classe
InputManagerService .
Et voici les mWindowManagerCallbacks dans
InputMonitor :
if (appWindowToken != null && appWindowToken.appToken != null) {
Examinons de plus près inputDispatchingTimedOut (). Ici, nous montrons simplement le message via l'ActivityManager sur l'expiration du délai d'expiration et laissons l'utilisateur décider d'annuler l'action ou de continuer à attendre. Et c'est dans
ActivityManagerService que AppErrors est appelé en cas de plantage ou d'ANR.
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(); }
Les principales causes de l'ANR
- Verrouillage entrée / sortie
- Congestion du réseau
- Blocage du fil
- Boucle sans fin
- La logique métier prend trop de temps
Éviter l'ANR
- Le thread d'interface utilisateur principal exécute la logique associée uniquement à l'interface utilisateur;
- Des calculs complexes (par exemple, opérations de base de données, opérations d'entrée-sortie, opérations de réseau, etc.) sont effectués dans un flux distinct;
- Utilisez le gestionnaire pour interagir entre le thread d'interface utilisateur et le flux de travail;
- Utilisez RxJava etc. pour gérer les opérations asynchrones.
Comment attraper ANR
PS Je publie toutes les sélections dans la chaîne de télégramme
@paradisecurity .