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:
<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>
Alles anzeigen
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:
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);
}
}
Alles anzeigen
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:
<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>
Alles anzeigen
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:
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);
}
}
Alles anzeigen
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...
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...
Wie macht ihr sowas?
Im Voraus schonmal vielen Dank für jede Idee oder Denkanstoß.