Crash — het onverwacht stoppen van een mobiele app door een onverwerkte uitzondering of fatale systeemfout. Volgens Firebase Crashlytics krijgt ongeveer 2% van de gebruikers dagelijks te maken met crashes, en elke crash vermindert de retentie met 10–20%. Inzicht in de oorzaken en preventiemethoden van crashes is een verplichte vaardigheid voor een mobiele ontwikkelaar.
Belangrijkste punten
Crash — is het onverwacht stoppen van een app veroorzaakt door een onverwerkte uitzondering of een fataal systeemsignaal dat niet is afgehandeld in de app-code. Wanneer het systeem of de virtuele machine (JVM, ART) een fatale toestand detecteert — NullPointerException, IndexOutOfBoundsException, OutOfMemoryError — stopt het onmiddellijk het proces en verwijdert het uit het geheugen. De gebruiker ziet de app plotseling sluiten zonder enige systeemfoutmelding. Volgens Google verliezen apps met een crash-free percentage onder 99% tot 20% van hun actieve gebruikers per maand.
Op Android verschilt het crashafhandelingsmechanisme van desktop systemen. In plaats van een debug-dialoog met stack trace, doodt Android simpelweg het proces en slaat geen gedetailleerde informatie op. Het verzamelen van crashinformatie is de taak van bibliotheken van derden (Crashlytics, Sentry, Bugsnag), die uitzonderingen onderscheppen via Thread.setDefaultUncaughtExceptionHandler voordat het proces wordt beëindigd.
iOS gebruikt een vergelijkbaar mechanisme met NSException en Mach exceptions voor het afhandelen van fatale fouten. Bij een onverwerkte uitzondering beëindigt het systeem de app en wordt het rapport opgeslagen als een .crash-bestand. Het verzamelen van crashes op iOS vereist integratie met Crashlytics of het ingebouwde rapport via Xcode Organizer.
Vijf categorieën crashes dekken 90% van alle crashes in mobiele apps. Inzicht in elk type helpt bij het sneller diagnosticeren en oplossen van problemen in de productieomgeving.
NullPointerException (NPE) — het meest voorkomende type crash in alle Java/Kotlin-apps. Ontstaat bij het aanroepen van een methode of het benaderen van een veld van een object dat null is. Typische scenario's: niet-geïnitialiseerd Activity-veld bij schermrotatie, null-antwoord van de server bij JSON-deserialisatie, onvoorzichtige navigatie door de RecyclerView-adapter.
Kotlin lost het NPE-probleem op taalniveau op via null-veilige typen: String? kan niet worden gebruikt zonder expliciete controle. Java-compatibiliteit en Reflection creëren echter nog steeds risico's. Gebruik @NonNull- en @Nullable-annotaties en schakel strictNullChecks in bij statische analyse tools.
fun safeLength(text: String?): Int {
return text?.length ?: 0 // veilige null-afhandeling
}
IndexOutOfBoundsException ontstaat bij het benaderen van een niet-bestaande index van een lijst of array. Veelvoorkomend scenario: verwijderen van een element uit RecyclerView zonder synchronisatie met de adapter, multi-thread modificatie van ArrayList zonder vergrendeling, onjuiste positieberekening in ViewPager. ConcurrentModificationException — een nauwe verwant bij gelijktijdige iteratie en modificatie van collecties.
Gebruik CopyOnWriteArrayList voor multi-thread toegang of Lock-free collecties uit java.util.concurrent. Voor synchronisatie met de UI gebruik DiffUtil, dat het verschil tussen oude en nieuwe lijst veilig en efficiënt berekent.
ClassCastException ontstaat bij het converteren van een object naar een incompatibel type. In Android typische oorzaken: onjuist ViewHolder-type in RecyclerView (verschillende celtypen zonder correcte getItemViewType), onjuiste Fragment-conversie bij navigatie, Serializable-objecten met verschillende klasseversies.
Gebruik Kotlins veilige conversie via de operator as?, die null retourneert bij type-incompatibiliteit. In Java — controle via instanceof voor conversie. Voor Parcelable-objecten moet u in elke klasse CREATOR declareren.
IllegalStateException signaleert het aanroepen van een methode in een ongeschikte objectstatus. Typisch voorbeeld in Android — getSupportFragmentManager() na onSaveInstanceState, wanneer commit() van de fragment niet is toegestaan. Een ander veelvoorkomend geval — het aanroepen van dismiss() op een reeds gesloten dialoog.
Controleer de levenscyclusstatus vóór bewerkingen met FragmentManager. Gebruik commitAllowingStateLoss() alleen wanneer u zeker weet dat statusverlies niet kritisch is. Maak in Kotlin DSL-achtige builders die onjuiste toestanden op typeniveau uitsluiten.
Native Crash ontstaat in native C/C++-code bij geheugenschending: toegang via null-pointer, double-free, stack buffer overflow. In Android treden dergelijke crashes op in NDK-bibliotheken, game-engines (Unity, Unreal) en systeemafhankelijkheden. Native Crash wordt NIET onderschept door Thread.setDefaultUncaughtExceptionHandler — het doodt het proces onmiddellijk.
Voor diagnose van native crashes gebruikt u minidump-bestanden (Breakpad) of Android-tombstones. Firebase Crashlytics ondersteunt het verzamelen van native crashes via de NDK SDK. Op iOS wordt hetzelfde probleem opgelost via PLCrashReporter.
Drie tools domineren de markt voor mobiele crashrapportage. Elk biedt stack trace verzameling, aggregatie per app-versie en meldingen van nieuwe crashes.
Crashlytics — de populairste crashreporter voor mobiele apps, onderdeel van het Firebase-ecosysteem. Het verzamelt automatisch stack trace, apparaatgegevens, OS-versie en aangepaste gebruikerssleutels. Integratie duurt 10 minuten via Firebase Console en Gradle Plugin. Crashlytics ondersteunt ook echte logs (Logcat) en aangepaste tracking.
FirebaseCrashlytics.getInstance()
.setCustomKey("current_screen", "ProfileFragment")
FirebaseCrashlytics.getInstance()
.log("User tapped login button")
Sentry — een alternatief voor Crashlytics met een flexibeler filtersysteem en ondersteuning voor 90+ platforms. In tegenstelling tot Firebase biedt Sentry een self-hosted server voor bedrijven met strikte databeveiligingseisen. Sentry ondersteunt distributieve tracking, breadcrumbs en integratie met CI/CD-pipelines.
Bugsnag onderscheidt zich door ondersteuning voor ernstgebaseerde waarschuwingen: het verdeelt crashes in kritiek, fout en waarschuwing. AppCenter van Microsoft — een gratis tool met basisfunctionaliteit voor kleine projecten. Beide ondersteunen Android, iOS, React Native en Flutter.
Analyse van een crash is het proces van het reconstrueren van het volledige beeld van de gebeurtenis. Stack trace toont alleen het laatste foutpunt, maar geeft geen context die tot het probleem leidde. Een professionele aanpak omvat vier fasen.
Eerste fase — het lezen van de stack trace. Bepaal de klasse, methode en regel code waar de uitzondering plaatsvond. Volg de aanroepketen van boven naar beneden: de laatste regel in de stack is de crashlocatie, en de bovenste regels zijn de aanroepvolgorde. Deobfuscatie (ProGuard/R8-mapping) is verplicht voor productiebuilds.
Tweede fase — apparaatcontext. Crashlytics toont het apparaatmodel, de OS-versie, het beschikbare geheugen en de app-versie. Bijvoorbeeld, een crash alleen op Samsung Galaxy S10 met Android 11 wijst op een probleem met een specifieke versie van One UI, niet op een algemene codefout.
Derde fase — reproductie op een testapparaat. Als de crash niet stabiel reproduceerbaar is, vraag de gebruiker om exacte stappen of gebruik Remote Config voor logging vóór het problematische codegedeelte. AB-testen van de fix op een deel van het publiek helpt de oplossing te bevestigen.
Vierde fase — monitoring na de fix. Na het publiceren van de fix, observeer de crashfrequentie gedurende 3–5 dagen. Als de crash volledig is verdwenen — heeft de fix gewerkt. Als de frequentie is gedaald maar niet naar nul is gegaan — bestaat er een tweede scenario dat aparte analyse vereist.
Systematische aanpak voor crashpreventie omvat statische analysetools, verplicht testen van randgevallen en correcte foutafhandeling op alle niveaus van de app.
Detekt (Kotlin) en Lint (Android) vinden potentiële problemen in de compilatiefase: ongebruikte variabelen, potentiële NPE, onjuist API-gebruik. Schakel deze tools in de CI-pipeline in met een foutdrempel. Bijvoorbeeld, Detekt met een configuratie van 30+ waarschuwingen of error-blocking laat de build niet door.
Dekking van belangrijke gebruiksscenario's met unit-tests is de basisbescherming tegen regressie-crashes. Test datamodellen, ViewModel en UseCase-lagen met randgevallen: null-waarden, lege lijsten, ongeldige JSON. UI-tests via Espresso of Compose Test dekken kritieke flows: authenticatie, betaling, onboarding.
Ontwerp de app zo dat een fout in één module niet het hele scherm laat crashen. Gebruik catch-blokken op ViewModel-niveau met het retourneren van een fallback-status: een placeholder tonen in plaats van een lijst, gecachte gegevens bij netwerkuitval, een reserveafbeelding bij laadfouten. Dit verandert een potentiële crash in een beheersbaar UX-scenario.
Staged rollouts — de standaardpraktijk van Google Play en App Store: een nieuwe versie wordt uitgerold naar 5%, vervolgens 20% en uiteindelijk 100% van het publiek met een interval van 1–3 dagen. In elke fase wordt de crashfrequentie gemonitord: als het crash-free percentage onder 99,5% daalt, wordt de uitrol automatisch gestopt. Firebase Remote Config maakt het mogelijk problematische functies uit te schakelen zonder een nieuwe versie te publiceren.
Renovate of Dependabot in CI controleren automatisch bibliotheken op bekende kwetsbaarheden en kritieke bugs. Het bijwerken van één afhankelijkheid kan een hele klasse crashes elimineren. Test updates echter in een staging-omgeving vóór uitrol naar productie — een nieuwe versie van een bibliotheek kan incompatibele wijzigingen bevatten.
Veelgestelde vragen
Nee. Een deel van de crashes wordt veroorzaakt door factoren buiten de controle van de ontwikkelaar: systeemfouten, hardware problemen, firmware-incompatibiliteit. Het doel is om de frequentie te verlagen naar 0,1% of lager, en de resterende crashes te minimaliseren qua reactietijd.
Crashreporter verzamelt stack trace, geheugenstatus en apparaatinfo op het moment van de crash. Analytics verzamelt gedragsgegevens van gebruikers. Crashlytics combineert beide benaderingen en biedt crashcontext samen met aangepaste gebruikerssleutels.
ProGuard en R8 verduisteren code ter bescherming van intellectueel eigendom. Voor deobfuscatie laadt u het mapping-bestand in Crashlytics bij publicatie. Zonder mapping-bestand toont de stack trace a.a(), b.b() in plaats van echte klasse- en methodenamen.
Via Thread.setDefaultUncaughtExceptionHandler op Android: de bibliotheek registreert zijn eigen handler, die als eerste de onverwerkte uitzondering ontvangt, gegevens opslaat en pas daarna het proces beëindigt. Op iOS wordt NSSetUncaughtExceptionHandler gebruikt voor NSException en Mach exception handler voor signalen.
Fataal — de app is beëindigd. Niet-fataal (gevangen uitzondering) — de ontwikkelaar heeft de uitzondering opgevangen via try-catch, maar dit kan wijzen op een potentieel probleem. Crashlytics onderscheidt deze typen en maakt het mogelijk non-fatal apart te filteren om het dashboard niet te vervuilen.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook