Unbehandelte Ausnahme (UnCaughtException) abfangen und Dialog anzeigen

H

Harry500

Neues Mitglied
8
Hallo zusammen,

ich habe vor, Ausnahmen, die nicht innerhalb Try-Catch-Blöcken abgefangen wurden, global abzufangen, und einen Dialog anzuzeigen. Eigentlich ist das nichts Besonderes, in anderen Programmiersprachen habe ich das mit relativ wenig Aufwand schon umsetzen können. Aber unter Android bekomme ich es einfach nicht hin. Nachdem ich mir einige Beispiele zu diesem Thema zusammengesucht habe, hier mal mein Versuch:

Ich erstelle eine neue Klasse "ThisApplication", die von der Klasse Application ableitet. Diese Klasse wird im Manifest unter dem application-Tag mit dem Attribut "name" angegeben, damit die Klasse auch tatsächlich als Application-Klasse verwendet wird. Im Manifest sieht das dann so aus:
Code:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.dual_mode.moretimer">
    <application
        android:name=".ThisApplication"
        android:allowBackup="true"
        android:icon="@mipmap/icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme_Light">
        ...
    </application>
</manifest>
In der Klasse "ThisApplication" überschreibe ich die onCreate-Callbackmethode, um dort den Standard-Handler für nicht abgefangene Ausnahmen auf meinen eigenen Ereignishandler umzuleiten. Gleichzeitig referenziere ich den vorherigen Standard-Handler, um diesen am Schluss meines eigenen Handlers wieder aufrufen zu können. In meiner eigenen Callback-Prozedur erstelle ich einen impliziten Intent, der eine Activity meiner eigenen App starten soll, nachdem sich die Haupt-Activity über die aufgetretene unbehandelte Ausnahme letztendlich verabschiedet hat. Die neue Activity, die über den impliziten Intent gestartet wird, soll als Dialog geöffnet werden. Die "ThisApplication"-Klasse sieht so aus:
Code:
public class ThisApplication extends Application
{
    Thread.UncaughtExceptionHandler originalUncaughtExceptionHandler;
    @Override
    public void onCreate ()
    {
        originalUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
        {
            @Override
            public void uncaughtException (Thread thread, Throwable e)
            {
                handleUncaughtException (thread, e);
            }
        });
        super.onCreate();
    }
    public void handleUncaughtException (Thread thread, Throwable e)
    {
        e.printStackTrace();
        Intent intent = new Intent ();
        intent.setAction ("de.mydomain.myapp.action.PROCESS_LOG");
        intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
        if (intent.resolveActivity(getPackageManager()) == null) {
            Log.d("ThisApplication","No receiver");
        } else {
            Log.d("ThisApplication", "Intent start");
            startActivity(intent);
        }
        originalUncaughtExceptionHandler.uncaughtException(thread, e);
    }
}
Damit meine App den Intent auch auffängt, und die passende Activity mit dem Namen "ProcessLogActivity" auch startet, wird diese Activity mit einem Intent-Filter wie folgt in der Manifest-Datei ergänzt:
Code:
<activity
    android:name=".ProcessLogActivity"
    android:windowSoftInputMode="stateHidden"
    android:theme="@style/ProcessLogActivity"
    android:process=":report_process"
    >
    <intent-filter>
        <action android:name="de.mydomain.myapp.action.PROCESS_LOG" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
Zu guter Letzt hier noch der Quellcode der eigentlichen Activity, die als Dialog erscheinen soll. Hier passiert erstmal nichts Dramatisches, da der Dialog erstmal nur angezeigt werden soll. Darüber hinaus hat er noch keine Funktionalität:
Code:
public class ProcessLogActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature (Window.FEATURE_NO_TITLE);
        setFinishOnTouchOutside (false);
        Log.d("ThisApplication", "Intent received");
        setContentView(R.layout.activity_process_log);
    }
}
Das Ergebnis ist, dass nach einer unbehandelten Ausnahme wieder der Standard-Dialog von Android erscheint, der anzeigt, dass die App leider geschlossen werden musste. Hinter diesem Standard-Dialog von Android ist mein eigenes Dialogfenster abgedunkelt zu sehen. Der Intent wurde also offenbar korrekt abgegeben und von meiner App wieder aufgefangen und die ProcessLogActivity gestartet. Allerdings wird, nachdem das Standard-Dialogfenster mit "OK" bestätigt wurde, nicht nur die beendete App geschlossen, sondern auch mein eigener Dialog. Wenn ich...
Code:
android.launchmode="singleInstance"
...in der Manifest-Datei der Dialog-Activity ergänze, verschwindet der Dialog ebenso, kann aber durch das Menü der zuletzt verwendeten Apps wieder hervorgeholt werden. Das macht auf mich den Eindruck, als ob der Dialog nicht vollständig unabhängig von dem vorherigen Process / Task gestartet wurde.

Hat jemand eine Idee, wo hier der Fehler liegt, oder wie ein entsprechendes Vorhaben umgesetzt werden kann? Normalerweise möchte man ja als Entwickler auch über unvorhergesehenes Fehlverhalten der App informiert werden, um die App zu korrigieren und verbessern. Ich weiß, es gibt auch umfangreiche Packages hierzu, die in die eigene App hineinkompiliert werden können, und die diverse Funktionalitäten in dieser Richtung bieten, allerdings habe ich nach dem obigen "Fehlschlag" auch schon mit dem Package ACRA experimentiert, wo ich aber bei der Anzeige von entsprechenden Dialogen aus diesem Package auf ähnliche Probleme stoße... :huh:

Wie macht ihr sowas?

Im Voraus schonmal vielen Dank für jede Idee oder Denkanstoß.
 
Guten Morgen Harry und willkommen im Forum.

Ich bin heute unterwegs, habe deinen Source also nicht genau studieren können.

Ich benutze die ACRA ohne Probleme

Da Acra ein JSon erstellt, pushe ich mir die Ereignisse ( auch in einer Singleton) auf einen Raspberry.

Ich meine aber mich dunkel zu erinnern , dass man das Json nicht durch die Gegen schicken muss,
sondern auch Lokal als String erhält - dann wärst du bereits schon am Ziel.

Mehr dann erst heute Abend - wenn noch bedarf besteht
 
Hallo und vielen Dank für Deine Antwort.

Ja, das ist richtig, bei ACRA ist es nicht nötig, selbst den Weg über einen Intent zu gehen, sondern man kann den Dialog direkt aus der "noch laufenden App heraus" öffnen, und zwar durch Angaben in der @ReportCrashes-Annotation direkt vor der angeleiteten Application-Klasse. Aber - wie gesagt - ich bekomme den Dialog auch hier nur für einen ganz kurzen Moment zu Gesicht. Bei der Variante mittels ACRA wird zwar kein Android-Standard-Dialog mehr angezeigt, aber dafür schließt sich meine App sofort und den Dialog über ACRA sehe ich nur für einen Bruchteil einer Sekunde, bevor nur noch der Homescreen zu sehen ist.

Wenn Du mehr Informationen zu meinen Einstellungen mittels ACRA sehen möchtest, poste ich hier gern noch meine Vorgehensweise über ACRA.
 
Jetzt verstehe ich auch was du genau meinst.

Vereinfacht : Da die App abstürtzt, ist natürlich nicht mehr viel mit einem Dialog :)

Und wenn du das Ergebnis der ACRA wegschreibst, damit es für die "Zukunft" bleibt ? (DB / ASCII File)
(und dann z.b. gesondertes "Anzeige"-Package per Intent aufrufen)
 
Über ACRA sollte ja der ACRA-Dialog - nachdem die eigene App beendet wurde - trotzdem erscheinen (ohne zusätzliches Intent) - dafür binde ich ja ACRA ein, und dafür gibt es ja auch die Einstellungen über die Annotation - eben damit man den Weg über einen zusätzlichen Intent nicht zu nehmen braucht (soviel zur Theorie...). Aber da es eben nicht funktioniert, würde ich lieber meinen eigenen Weg mit dem Intent gehen.

EDIT: Zur Vollständigkeit hier mal meine Vorgehensweise, wenn ich ACRA benutze. Zum Einen füge ich die @ReportCrashes-Annotation zur Application-Klasse hinzu. Zum Anderen wird ACRA in der attachBaseContext-Callbackmethode initialisiert. Die Klasse sieht dann so aus:
Code:
import android.app.Application;
import android.content.Context;

import org.acra.ACRA;
import org.acra.ReportingInteractionMode;
import org.acra.annotation.ReportsCrashes;
import org.acra.config.ACRAConfiguration;
import org.acra.config.ACRAConfigurationException;
import org.acra.config.ConfigurationBuilder;

@ReportsCrashes(
        formUri = "http://yourserver.com/yourscript",
        mode = ReportingInteractionMode.DIALOG,
        resDialogText = R.string.app_name
)
public class ThisApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);

        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(this);
        configurationBuilder.setBuildConfigClass(BuildConfig.class);

        final ACRAConfiguration config;
        try {
            config = configurationBuilder.build();
            ACRA.init(this, config);
        } catch (ACRAConfigurationException e) {
            e.printStackTrace();
        }
    }
}
Für die Einrichtung von ACRA füge ich folgenden Verweis in die gradle.build-Datei ein:
Code:
compile 'ch.acra:acra:4.9.0'
Da ich die Informationen des ACRA-Dialogs (für den ersten Test) nicht tatsächlich über eine Internetverbindung irgendwo hin absenden will, wäre eine Anforderung der Internet-Berechtigung im Grunde nicht erforderlich, schon auch deshalb, weil ich später meinen eigenen Dialog über ACRA verwenden will. Da ich für die App selbst aber auch eine Internetverbindung benötige, ist eine entsprechende Berechtigung in der Manifest-Datei hinterlegt:
Code:
<uses-permission android:name="android.permission.INTERNET"/>
 
Zuletzt bearbeitet:
Hallo,

für alle, die vielleicht auch mal an diesem Problem verzweifeln, stelle ich hier mal die Lösung rein, die ich gerade gefunden habe. Das Problem hängt damit zusammen, dass die App über die Funktion "Debugging" des Android Studios ausgeführt wurde, und dann der ACRA-Mechanismus irgendwie von dem Debugger abgefangen wird, und sich so kein Effekt zeigt. Startet man anschließend die auf dem virtuellen Android-System installierte App dort manuell erneut, zeigt sich auch der ACRA-Dialog nach der Exception. :rolleyes2:

Zwar hab ich jetzt noch das Problem, bei einem eigenen CrashReportDialog über die ACRA-Objekte an die Reportdaten heranzukommen, aber da forsche ich nochmal etwas nach. Falls aber jemand dazu einen Tipp hat, würde ich mich auch hierzu über einen Hinweis freuen.
 
  • Danke
Reaktionen: swa00
Hallo Harry

Danke für Dein Feedback.
Es ist immer wieder schön , wenn sich die User auch zurückmelden :)
 
  • Danke
Reaktionen: lordzwieback
Eine andere Möglichkeit wäre den error stack trace einfach in ein File abzuspeichern. Danach die App komplett beenden. Und mit ein PendingIntent neu starten, und dann den Text im File anzeigen oder per Internet versenden.

Wenn irgendwas komplett abstürzt, solle man es nicht künstlich am Leben zu erhalten.
 

Ähnliche Themen

W
  • waltsoft
Antworten
4
Aufrufe
938
waltsoft
W
D
  • Data2006
3 4 5
Antworten
84
Aufrufe
3.705
jogimuc
J
M
  • MikelKatzengreis
Antworten
5
Aufrufe
128
swa00
swa00
Zurück
Oben Unten