When your app fails to respond to interactions in real time it causes user frustration and can lead them to abandon your app altogether.
An app hang or freeze is a specific instance of the main thread failing to respond in a reasonable amount of time and can be caused by performing CPU intensive work or performing blocking I/O on the main thread. If your app hangs for 5 seconds or longer, it will trigger an Application Not Responding (ANR) event, which is reported to your BugSnag dashboard by default.
You can also use the bugsnag-plugin-android-apphang plugin to detect and report app hangs that last for a shorter period of time, helping you to identify and fix performance issues before they impact your users. By monitoring the main thread looper, the plugin sends the stack trace of the main thread when an app hang is detected, helping you to identify the underlying cause. The stack trace will be captured at the point the hang is first detected.
This plugin can either be considered an alternative to ANR detection, or can be used alongside it to provide additional visibility into shorter app hangs. Both signals will be detected and reported to your BugSnag dashboard, with hangs typically being reported as breadcrumbs leading up to the ANR event.
Install bugsnag-plugin-android-apphang on devices running Android 11+ (API 30) by adding the dependency to your app/build.gradle or build.gradle.kts file:
dependencies {
implementation("com.bugsnag:bugsnag-plugin-android-apphang:6.+")
}
dependencies {
implementation("com.bugsnag:bugsnag-plugin-android-apphang:6.+")
}
Then add the plugin to your configuration:
BugsnagAppHangPlugin bugsnagAppHangPlugin = new BugsnagAppHangPlugin();
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagAppHangPlugin);
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
addPlugin(BugsnagAppHangPlugin())
})
Please note that v6.0.0 or above of bugsnag-android-core is required for this plugin.
The plugin can be configured by passing it an AppHangPluginConfiguration object with one or more of the following options:
appHangThresholdMillisThe length of the app hang (in milliseconds) that will trigger an event:
AppHangConfiguration appHangPluginConfiguration = new AppHangConfiguration();
appHangPluginConfiguration.setAppHangThresholdMillis(5000);
Configuration config = Configuration.load(this);
config.addPlugin(new BugsnagAppHangPlugin(appHangPluginConfiguration));
Bugsnag.start(this, config);
Bugsnag.start(Configuration.load(this).apply {
addPlugin(
BugsnagAppHangPlugin(
AppHangConfiguration(
appHangThresholdMillis = 5000
)
)
)
})
The default value is 3000 (3 seconds).
watchedLooperThe Looper instance to monitor for app hangs. By default, this is set to the main thread looper:
AppHangConfiguration appHangPluginConfiguration = new AppHangConfiguration();
appHangPluginConfiguration.setWatchedLooper(Looper.myLooper());
BugsnagAppHangPlugin bugsnagAppHangPlugin = new BugsnagAppHangPlugin(appHangPluginConfiguration);
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagAppHangPlugin);
Bugsnag.start(this, config);
Bugsnag.start(Configuration.load(this).apply {
addPlugin(
BugsnagAppHangPlugin(
AppHangConfiguration(
watchedLooper = Looper.myLooper()
)
)
)
})