Error and Exception Monitoring for Android App

⚙️ Configure Error, Exception, and Crash Monitoring for Android

📖 Overview

The GermainUX Mobile App library can collect:

Item

Crashes caused by unhandled exceptions

Handled exceptions reported by application code

Application errors that do not throw an exception

Selected Android StrictMode violations, when enabled and supported

Application uptime and closure context associated with a crash

Error data can be correlated with the application version, Android version, device, user session, screen, fragment, transaction, and preceding application events.

warning Error Types

Use the appropriate GermainUX event for each condition:

Type

When to use

Crash

The application terminates because of an unhandled failure

Handled exception

An exception occurred but the application caught and handled it

Application error

A meaningful failure occurred without a Java or Kotlin exception

StrictMode violation

Android detected a configured development or runtime policy violation

Do not report expected user validation, such as a required field left empty, as an application error unless the software itself is failing to operate as intended.

🤖 Automatic Crash Detection

Unhandled-exception monitoring is enabled automatically after GermainUX initialization unless it is explicitly disabled:

config.setAutomaticUnhandledExceptionsMonitoring(false);

When an unhandled exception terminates the application, GermainUX attempts to capture:

Attribute

Exception type

Error message

Stack trace

Crash timestamp

Application version

Android and device context

Active user session

Related screen or fragment

Application uptime

Application-closure event

Delivery is attempted before the application process terminates, but Android does not guarantee enough execution time to transmit crash telemetry immediately.

⛔ Disable Automatic Crash Detection

Disable automatic monitoring only when required, such as when:

Scenario

Another crash handler must remain solely responsible for uncaught exceptions.

The application implements a custom crash-reporting workflow.

Crash reporting is disabled for a specific build type.

Consent or privacy requirements prevent automatic collection.

☕ Java

GermainAPMConfiguration config =
    new GermainAPMConfiguration(
        "https://YOUR_GERMAINUX_HOST/ingestion/fact"
    );

config.setAutomaticUnhandledExceptionsMonitoring(false);

GermainAPM.init(this, config);

🚀 Kotlin

val config = GermainAPMConfiguration(
    "https://YOUR_GERMAINUX_HOST/ingestion/fact"
)

config.setAutomaticUnhandledExceptionsMonitoring(false)

GermainAPM.init(this, config)

When multiple crash libraries are installed, verify that their uncaught-exception handlers are compatible and that the original handler chain is preserved.

🤝 Report a Crash Explicitly

Use collectCrash() only when the application is treating the condition as a crash or terminal failure.

☕ Java

try {
    runCriticalOperation();
} catch (Throwable error) {
    GermainAPM.collectCrash(
        "CriticalOperationCrash",
        error,
        false
    );

    throw error;
}

🚀 Kotlin

try {
    runCriticalOperation()
} catch (error: Throwable) {
    GermainAPM.collectCrash(
        "CriticalOperationCrash",
        error,
        false
    )

    throw error
}

Parameters:

Parameter

Description

Name

Stable category used to identify the crash

Throwable

Exception and stack-trace information

StrictMode flag

true only when the event represents a StrictMode violation

collectCrash() also records application closure and uptime context. Do not use it for a condition after which the application continues normally. Use collectException() or collectError() instead.

Avoid catching Throwable solely for monitoring in normal application code. The preceding example represents a terminal boundary where the failure is reported and rethrown.

💡 Report Handled Exceptions

Use collectException() inside existing exception-handling logic when the exception is operationally meaningful.

📝 Basic example

Java:

try {
    loadCustomerData();
} catch (IOException error) {
    GermainAPM.collectException(error);

    showCachedData();
}

Kotlin:

try {
    loadCustomerData()
} catch (error: IOException) {
    GermainAPM.collectException(error)

    showCachedData()
}

The application remains responsible for handling the exception. Reporting it to GermainUX does not recover the failed operation or alter the application flow.

🏷️ Custom exception name

Use a stable custom name when the default exception class does not provide enough business or technical context.

Java:

try {
    submitOrder();
} catch (IOException error) {
    GermainAPM.collectException(
        "OrderSubmissionException",
        error,
        false
    );

    displayRetryOption();
}

Kotlin:

try {
    submitOrder()
} catch (error: IOException) {
    GermainAPM.collectException(
        "OrderSubmissionException",
        error,
        false
    )

    displayRetryOption()
}

The third parameter identifies whether the reported exception represents a StrictMode violation.

Use consistent names rather than including record IDs, user names, timestamps, or dynamic error values in the event name.

❗ Report Application Errors

Use collectError() when an important failure occurs without an exception.

Examples include:

Example

Invalid response received from a service

Required application data missing

Business transaction rejected unexpectedly

Local data synchronization failed

Expected result not produced

Application entered an invalid state

☕ Java

if (!response.isSuccessful()) {
    GermainAPM.collectError(
        "CustomerSyncFailed",
        "The customer synchronization request failed."
    );

    displayRetryOption();
}

🚀 Kotlin

if (!response.isSuccessful) {
    GermainAPM.collectError(
        "CustomerSyncFailed",
        "The customer synchronization request failed."
    )

    displayRetryOption()
}

Keep error content concise and free of sensitive data.

Do not pass:

Do not pass

Passwords

Authentication tokens

Payment information

Personal or health information

Full request or response bodies

Database records

Secret URLs or query parameters

🔍 StrictMode Violations

Android StrictMode can identify development and runtime policy violations such as:

Violation

Disk reads or writes on monitored threads

Network operations on the main thread

Slow calls

Resource mismatches

Leaked closable objects

Leaked activities or registrations

File URI exposure

Cleartext network use

Untagged sockets

Unsupported non-SDK API usage

The violations available depend on the Android version and the StrictMode policies enabled by the application.

StrictMode findings are not automatically equivalent to production crashes. Some violations log a warning, while others can be configured to terminate the application. Categorize them according to their actual behavior and impact.

Use StrictMode cautiously in production. Validate the selected policies and penalties in a test environment before rollout.

🏷️ Categorize Errors in GermainUX

Configure categories that distinguish:

Category

Application crashes

Handled exceptions

Application errors

StrictMode violations

User-facing software errors

Silent software errors

Expected user validation

Network and integration failures

Data and synchronization failures

This prevents user validation and low-value diagnostic events from inflating the KPI used for software failures.

📈 Analyze Errors

Use GermainUX dashboards to analyze errors by:

Dimension

Error or exception name

Exception class

Application version

Android version

Device manufacturer and model

Screen or fragment

Transaction

User session

User or role, when approved

First and last occurrence

Affected users and sessions

Frequency and trend

Prioritize errors based on user impact, recurrence, severity, affected business process, and whether they were introduced by a recent release.

🔔 Alerts

Configure alerts for conditions such as:

Alert condition

New crash signature

Increased crash rate

Critical transaction failure

Repeated handled exception

Application-version regression

Error affecting many users

Sudden increase in StrictMode violations

Missing crash data after a known failure

Avoid sending an alert for every individual occurrence of a high-volume error. Use aggregation, minimum affected-user counts, persistence, and severity rules.

🔒 Privacy and Obfuscation

Before enabling error reporting:

Action

Review exception messages and stack traces for sensitive data.

Anonymize or exclude sensitive fields.

Avoid dynamic personal data in exception names.

Restrict access to diagnostic information.

Retain R8 or ProGuard mapping files for each release.

Protect mapping files because they reveal application structure.

Apply an appropriate retention period.

Obfuscated stack traces may require the corresponding mapping file to identify the original classes and methods.

✅ Validation

Test the integration in a nonproduction build:

  1. Initialize GermainUX.

  2. Report a controlled application error.

  3. Report a handled exception.

  4. Trigger an unhandled exception in a safe test scenario.

  5. Confirm that the crash is associated with the correct session.

  6. Verify application, version, device, screen, and transaction context.

  7. Confirm that the release build provides usable stack traces.

  8. Verify that sensitive values are excluded.

  9. Test alert thresholds and recipients.

  10. Confirm that another installed crash handler still works, if applicable.

🔧 Troubleshooting

💥 Unhandled crashes are not collected

Verify that:

Check

GermainUX initializes before the crash occurs.

Automatic unhandled-exception monitoring is enabled.

Another library has not replaced the GermainUX exception handler.

The device can reach the ingestion endpoint.

The release build includes the GermainUX library.

Privacy or processing rules do not discard the event.

A crash that terminates the process immediately may not be transmitted until the library has another opportunity to send retained telemetry, if supported by the installed version.

🔎 Handled exceptions are missing

Confirm that:

Check

collectException() executes.

The exception is not filtered by configuration.

The application remains active long enough to distribute telemetry.

The GermainUX application and environment are enabled.

The device has network connectivity.

📄 Stack traces are unreadable

Check:

Check

R8 or ProGuard configuration

Preservation of source and line-number attributes

Mapping-file retention

Installed library compatibility

Whether the exception was created without a meaningful stack trace

🔁 Duplicate crashes appear

Verify that:

Check

Notes

The same failure is not reported manually and automatically.


Multiple crash libraries are not forwarding the same event.


Retry or retained-event delivery is deduplicated by the configured processing rules.


ℹ️ Get More Information

GermainUX can help determine which monitoring, analytics and automation capabilities are appropriate for your Android App environment.

Contact GermainUX Support.

Component: Engine, Mobile App

Feature Availability: 2022.1 or later