2010-05-04 4 views
81

Ich möchte einen globalen nicht abgefangenen Ausnahme-Handler für alle Threads in meiner Android-Anwendung festlegen. In meiner Unterklasse Application habe ich eine Implementierung von als Standard-Handler für nicht abgefangene Ausnahmen festgelegt.Ideale Methode zum Festlegen von globalen nicht abgefangenen Ausnahmen Handler in Android

Thread.setDefaultUncaughtExceptionHandler(
       new DefaultExceptionHandler(this)); 

In meiner Implementierung, ich versuche, eine AlertDialog Anzeige entsprechende Ausnahmemeldung anzuzeigen.

Dies scheint jedoch nicht zu funktionieren. Immer wenn eine Ausnahme für einen Thread ausgelöst wird, der nicht behandelt wird, erhalte ich den Standard-OS-Standarddialog ("Sorry! -Application-has-stopped-expecteddialog").

Was ist die richtige und ideale Methode zum Festlegen eines Standardhandlers für nicht abgefangene Ausnahmen?

+1

Können Sie bitte den Code für das gleiche teilen .. –

+2

Wenn Sie Ihre Ausnahmen protokollieren möchten, sehen Sie sich http://acra.ch/ an. Mit ACRA können Sie Fehlerberichte an ein Google-Dokument oder an Sie per E-Mail senden. –

+1

@Alexander Oder Sie können einfach Google Analytics für Android verwenden und alle Ausnahmen protokollieren, die Sie möchten ... –

Antwort

23

eingestellt ist, dass alles, was Sie tun müssen, sein sollte. (Stellen Sie sicher, dass der Prozess danach angehalten wird - die Dinge könnten in einem unsicheren Zustand sein.)

Die erste Sache zu prüfen ist, ob der Android-Handler immer noch aufgerufen wird. Es ist möglich, dass Ihre Version aufgerufen wird, aber fatal versagt und der system_server einen generischen Dialog anzeigt, wenn der Prozess abstürzt.

Fügen Sie am oberen Rand Ihres Handlers einige Protokollnachrichten hinzu, um zu sehen, ob sie dort ankommen. Drucken Sie das Ergebnis von getDefaultUncaughtExceptionHandler, und werfen Sie dann eine nicht abgefangene Ausnahme ab, um einen Absturz zu verursachen. Behalten Sie die Logcat-Ausgabe im Auge, um zu sehen, was passiert.

+10

"eine nicht abgefangene Ausnahme zu werfen, um einen Absturz nach der Behandlung des Fehlers zu verursachen" ist immer noch wichtig. Ich habe es gerade erlebt. Meine App wurde gesperrt, nachdem ich die Ausnahme behandelt und keine nicht abgefangene Ausnahme ausgelöst habe. – OneWorld

+0

@OneWorld Jepp gleich hier - zumindest für den Sperrteil - scheint es keine Möglichkeit zu geben, die App vor dem Absturz zu "retten". – AgentKnopf

+0

@Zainodis Ich habe eine leichte Off-Topic-Antwort auf diese Frage gepostet, die einen Link zu Crittercism gibt - ich denke, sie haben eine Funktion, mit der Sie die App vor dem Absturz "speichern" können. Nicht sicher - Ich benutze nur die kostenlose Version atm. –

3

denke ich, dass in Ihrem uncaughtException() -Methode deaktivieren rufen Sie nicht previousHandler.uncaughtException(), wo previousHandler von

previousHandler = Thread.getDefaultUncaughtExceptionHandler(); 
3

FWIW Ich weiß, das ist ein wenig off-topic, aber wir haben Crittercism's free plan mit Erfolg verwendet. Sie bieten auch einige Premium-Funktionen, wie die Behandlung der Ausnahme, so dass die App nicht abstürzt.

In der kostenlosen Version sieht der Benutzer immer noch den Absturz, aber zumindest bekomme ich die E-Mail und den Stack-Trace.

Wir verwenden auch die iOS-Version (aber ich habe von meinen Kollegen gehört, dass es nicht ganz so gut ist).


Hier sind ähnliche Fragen:

1

Es funktioniert nicht, bis Sie

android.os.Process.killProcess(android.os.Process.myPid()); 

am sehr en nennen d Ihres UncaughtExceptionHandlers.

8

Ich veröffentlichte die einfache solution für die benutzerdefinierte Behandlung von Android Abstürzen vor langer Zeit. Es ist ein wenig hacky, aber es funktioniert auf allen Android-Versionen (einschließlich der Lollipop).

Zuerst ein bisschen Theorie. Die Hauptprobleme bei der Verwendung des nicht abgefangenen Ausnahmebehandlers in Android werden mit den Ausnahmen geliefert, die im Haupttool (auch als UI-Thread bezeichnet) ausgelöst werden. Und hier ist warum.Wenn die App startet System ActivityThread.main Methode aufruft, die die Main looper Ihrer App bereitet und beginnt:

public static void main(String[] args) { 
    … 
    … 
    Looper.prepareMainLooper(); 
    … 
    Looper.loop(); 
    throw new RuntimeException("Main thread loop unexpectedly exited"); 
} 

Hauptgreifer ist verantwortlich für die im UI-Thread gepostet Verarbeitung von Nachrichten (einschließlich aller Nachrichten an UI-Rendering und der Interaktion im Zusammenhang). Wenn eine Ausnahme im UI-Thread ausgelöst wird, wird sie von Ihrem Ausnahmebehandler abgefangen. Da Sie jedoch die Methode loop() nicht mehr verwenden, können Sie dem Benutzer keinen Dialog oder keine Aktivität mehr anzeigen, da niemand mehr zur Verarbeitung der UI benötigt wird Nachrichten für Sie.

Die vorgeschlagene Lösung ist recht einfach. Wir betreiben Looper.loop Methode von unserem eigenen und umgeben es mit Try-Catch-Block. Wenn eine Ausnahme abgefangen wird, verarbeiten wir sie wie gewünscht (z. B. starten Sie unsere benutzerdefinierte Berichtaktivität) und rufen Sie erneut die Methode Looper.loop auf.

Die folgende Methode demonstriert diese Technik (es sollte aus dem Application.onCreate Hörer aufgerufen werden):

private void startCatcher() { 
    UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler(); 

    // the following handler is used to catch exceptions thrown in background threads 
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler(new Handler())); 

    while (true) { 
     try { 
      Looper.loop(); 
      Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler); 
      throw new RuntimeException("Main thread loop unexpectedly exited"); 
     } catch (Throwable e) { 
      showCrashDisplayActivity(e); 
     } 
    } 
} 

Wie Sie sehen können der abgefangene Exception-Handler verwendet wird, nur für die im Hintergrund Fäden geworfen Ausnahmen. Die folgende Prozedur fängt diese Ausnahmen und breitet sie auf den UI-Thread:

static class UncaughtHandler implements UncaughtExceptionHandler { 

    private final Handler mHandler; 

    UncaughtHandler(Handler handler) { 
     mHandler = handler; 
    } 

    public void uncaughtException(Thread thread, final Throwable e) { 
     mHandler.post(new Runnable() { 
      public void run() { 
       throw new BackgroundException(e); 
      } 
     }); 
    } 
} 

Ein Beispiel-Projekt, das verwendet diese Technik auf meinem GitHub Repo verfügbar: https://github.com/idolon-github/android-crash-catcher

+0

Wie man sich denken kann, ist es auf diese Weise nicht nur möglich, benutzerdefinierte Fehlerdialog anzuzeigen, sondern auch den Benutzer die Ausnahme zu ignorieren und die Arbeit mit der Anwendung fortzusetzen (und obwohl es für die veröffentlichten Anwendungen eine schlechte Idee ist, könnte es während einer Debug- oder Testsitzung ziemlich praktisch sein). – Idolon

+0

Hi, während dies beim Erfassen nicht abgefangener Ausnahmen funktioniert, aber aus irgendeinem Grund gibt dieser Code immer Ausnahmen aus. Anfangs war es wegen der RuntimeException-Zeile, die Sie in der startCatcher-Methode haben, aber ich bekomme immer noch eine Ausnahme nach dem Entfernen. Ich bin mir nicht sicher, ob das erforderlich ist. Wie auch immer, die Ausnahme, die ich bekomme, ist 'java.lang.RuntimeException: Ausführung der Pause der Aktivität, die nicht fortgesetzt wird. Ich glaube, wenn ich versuche, meinen eigenen Looper zu starten, pausiert das System die Aktivität, die gerade beginnt? Ich bin mir nicht sicher, aber jede Hilfe würde geschätzt werden. Danke – sttaq

+0

auch, wenn ich den startCatcher entfernen, d. H. Die App ohne Ihren Code ausführen, dann funktioniert alles ohne Ausnahmen. – sttaq

Verwandte Themen