How To: Handle Uncaught Exceptions with Appygram in Android - GoGoCarl/appygram4j GitHub Wiki
Appygram4J support Appygram Traces, which allows you to send stack traces to Appygram and manage them with notifications just like you would any other message. It also has built-in counting capability to prevent excessive duplicates being sent, among other features. It's simple enough to send a trace explicitly for caught exceptions, as explained here, but here's how to handle uncaught exceptions with Android.
Step 1: Create an UncaughtExceptionHandler
This is an extension of Java's Thread.UncaughtExceptionHandler, and will be used to catch any Exceptions thrown by the system. Important to note, Android already does this for you when it reports that you app has crashed, and we don't want to get rid of this; rather, we want do our work in addition to what Android does.
public class AppygramDefaultExceptionHandler implements Thread.UncaughtExceptionHandler, AppygramEventHandler {
private final UncaughtExceptionHandler defaultHandler;
private Thread thread;
private Throwable ex;
public AppygramDefaultExceptionHandler() {
//Save the default handler from Android, we will use this later
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//A callback for after an Appygram has been sent
Appygram.Global.addAfterSendHandler(this);
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
this.thread = thread;
this.ex = ex;
AppygramTrace trace = Appygram.Global.createTrace(ex);
trace.setTopic("Exception");
trace.setSummary("Uncaught Exception");
/*
* If you store the logged-in user in your own implementation, you
* may want to access it here to send user-specific information
* with your Appygram Trace.
*/
if (MyApplication.user != null) {
trace.setEmail(user.getEmail());
trace.setName(user.getName());
}
try {
Log.d("Appygram", "Uncaught exception occurred, logging then exiting: " + ex.getMessage());
Appygram.Global.trace(trace);
} catch (Throwable t) {
//Some unknown error, but we still want to exit normally.
defaultHandler.uncaughtException(thread, ex);
}
}
@Override
public void afterSend(AppygramEvent event) {
//Checking for the thread ensures we don't exit when sending manual Traces
if (thread != null) {
Log.d("Appygram", "Message sent, uncaught exception thrown; Exiting now.");
defaultHandler.uncaughtException(thread, ex);
}
}
}
Now, you just need to attach the handler. Naturally, you want this to happen before any other operations in your application. So, for this example, this will be accomplished by giving Android an implementation of the Application class, which can be used to house any things that you want to do before launching your first Activity. There may be other ways, but this seems most logical as of this writing.
Step 2: Override the Application in the Manifest
Simple enough, just update the application
element in AndroidManifest.xml
, like so:
<application
android:name="com.example.android.MyApplication"
... >
Then, create a class com.example.android.MyApplication:
package com.example.android
public class MyApplication extends android.app.Application {
@Override
public void onCreate() {
...
super.onCreate();
}
}
Step 3: Initialize Appygram and attach the AppygramDefaultExceptionHandler
This step is best explained in code, so let's just get to it; this continues the implementation of MyApplication.java from above:
public class MyApplication extends android.app.Application {
/*
* Could be set and unset on login/logout, such that uncaught exceptions
* can access this and send user information with Traces. This is
* completely optional and implementation details will vary by application.
*/
public static User user = null;
@Override
public void onCreate() {
AppygramConfig config = new AppygramConfig("my-api-key");
/*
* It is required here that you allow threads, as Android will not
* allow network traffic on the main thread.
*/
config.setAllowThreads(true);
config.setLogToConsole(false);
config.setPlatform(Build.MANUFACTURER + " " + Build.MODEL + " (" + Build.DEVICE + ")");
config.setSoftware("Android " + Build.VERSION.RELEASE);
Appygram.configure(config);
AppygramDefaultExceptionHandler handler = new AppygramDefaultExceptionHandler();
//Set our custom handler as the default handler.
Thread.setDefaultUncaughtExceptionHandler(handler);
//Now continue with creating the app
super.onCreate();
}
}
Now, any uncaught exceptions will be sent to Appygram, then propagated to Android's exception handler to shut down the app.