StrictMode is een in de Android SDK ingebouwde ontwikkelaarstool die in realtime onbedoelde I/O-bewerkingen en netwerkoproepen op de hoofdthread van de app detecteert en rapporteert. Het corrigeert geen fouten, maar treedt op als detector — het gooit uitzonderingen of schrijft naar LogCat wanneer het ingestelde beleid wordt geschonden. Volgens Google, 2024 maakt een correcte configuratie van StrictMode het mogelijk om tot 80% van de prestatieproblemen al vóór de release van de app te detecteren.
Belangrijkste punten
StrictMode is een API die sinds API Level 9 (Android 2.3 Gingerbread) deel uitmaakt van de Android SDK. Het doel is om tijdens de runtime onbedoelde uitvoering van zware operaties op de hoofdthread (UI) te detecteren die de weergave van de interface kunnen blokkeren. De hoofdthread is verantwoordelijk voor het verwerken van gebruikersinvoer, de berekening van de lay-out en de weergave — elke blokkering langer dan 16 ms leidt tot een overgeslagen frame.
StrictMode volgt het principe “fail fast” — ontdek het probleem zo vroeg mogelijk, bij voorkeur op het moment dat het voor het eerst verschijnt. In plaats van te wachten op klachten van gebruikers over haperingen, krijgt de ontwikkelaar een signaal (logboeken, dialoog of crash) al tijdens de ontwikkeling. De tool vereist geen extra bibliotheken of Gradle-configuratie — een paar regels code in Application.onCreate is voldoende, en hij werkt automatisch op alle apparaten.
StrictMode is bedoeld voor alle Android-ontwikkelaars, ongeacht ervaring. Beginners helpt het om goede gewoonten te vormen (geen netwerkverzoeken in de UI-thread), ervaren ontwikkelaars kunnen er de kwaliteitscontrole in het CI/CD-pijplijn mee automatiseren. Grote projecten (Google, Uber, Spotify) schakelen StrictMode in debug-builds in met penaltyDeath en schakelen het in release-builds uit via een controle op BuildConfig.DEBUG.
StrictMode onderschept systeemoproepen die een thread kunnen blokkeren en vergelijkt ze met de set actieve policies. Als een oproep overeenkomt met een policy en op de hoofdthread wordt uitgevoerd, past StrictMode de ingestelde penalty toe. Het onderscheppingsmechanisme is geïmplementeerd via een hook binnen het proces — het gebruikt geen reflection en werkt met minimale overhead.
Bij activering van een policy injecteert StrictMode zijn eigen handler in het ingangspunt van systeemoproepen (FileInputStream, FileOutputStream, Socket, URLConnection). Wanneer de app bijvoorbeeld URLConnection.openStream op de hoofdthread aanroept, controleert StrictMode de huidige thread — als dit de main thread is, wordt de tool geactiveerd. Vanaf Android 6.0+ is het mechanisme versterkt: netwerkoproepen in de main thread genereren NetworkOnMainThreadException zelfs zonder StrictMode, maar StrictMode maakt ook controle over disk I/O mogelijk.
Elke policy kan een eigen type penalty of een combinatie hebben: penaltyLog — schrijven naar LogCat met een stacktrace, penaltyDialog — een dialoog tonen aan de gebruiker (alleen in debug), penaltyDeath — een uitzondering gooien en de app laten crashen, penaltyDropBox — gegevens opslaan in DropBoxManager voor latere analyse. Voor het CI/CD-pijplijn wordt penaltyDeath aanbevolen — dit garandeert dat geen enkele merge met een schending onopgemerkt blijft.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
}
StrictMode verdeelt het beleid over twee niveaus: ThreadPolicy (thread — wat niet op de hoofdthread mag) en VmPolicy (virtuele machine — geheugen- en resourcelekken). Beide niveaus worden onafhankelijk geconfigureerd en werken parallel.
Op threadniveau controleert StrictMode vier soorten schendingen: lezen van de schijf (detectDiskReads), schrijven naar de schijf (detectDiskWrites), netwerkoperaties (detectNetwork) en aangepaste trage oproepen (detectCustomSlowCalls). disk_read wordt geactiveerd bij elk lezen van SharedPreferences, SQLite of bestanden op de hoofdthread. network — bij HTTP-verzoeken, WebSocket- en Socket-verbindingen. In Android 11+ is detectUnbufferedIO toegevoegd voor het detecteren van niet-gebufferde I/O.
VmPolicy controleert lekken op het niveau van de virtuele machine ART: detectActivityLeaks (Activity's die niet zijn vernietigd), detectLeakedClosableObjects (niet gesloten Cursor, Stream, Socket), detectLeakedRegistrationObjects (niet opgeheven BroadcastReceiver, ServiceConnection). Als VmPolicy detecteert dat een Activity is gemaakt maar na de oproep van onDestroy niet is vernietigd, geeft het een volledige stack trace af — dit bespaart uren aan het debuggen van geheugenlekken.
| Beleid | Niveau | Wat detecteert het |
|---|---|---|
| detectDiskReads | Thread | Lezen van SharedPrefs, SQLite, bestanden in de UI-thread |
| detectDiskWrites | Thread | Schrijven naar SharedPrefs, SQLite, bestanden in de UI-thread |
| detectNetwork | Thread | Alle netwerkoperaties in de UI-thread |
| detectActivityLeaks | VM | Activity's die onDestroy overleven |
| detectLeakedClosableObjects | VM | Niet gesloten Cursor, Stream, Socket |
Via detectCustomSlowCalls kunt u eigen methoden markeren als “verdacht” en een waarschuwing krijgen bij overschrijding van een ingestelde drempel. Bijvoorbeeld: als uw methode loadUserProfile() meestal 5 ms duurt, maar in sommige gevallen 200 ms, wikkel hem dan in StrictMode.noteSlowCall("loadUserProfile"). Wanneer de duur de drempel overschrijdt (standaard 2000 ms), genereert StrictMode een penalty. De drempel wordt ingesteld via setSlowCallDurationThreshold.
De basisconfiguratie van StrictMode kost 10 regels code en gebeurt in de methode onCreate van een aangepaste Application-klasse. Hoofdregel: StrictMode wordt alleen ingeschakeld in debug-builds — in release-builds vertraagt het de app en kan het valse meldingen veroorzaken.
Maak een klasse die Application erft, registreer deze in AndroidManifest.xml via het kenmerk android:name en voeg de StrictMode-configuratie toe. ThreadPolicy.Builder schakelt alle detectoren en alle soorten penalty in (behalve dialog — die werkt alleen wanneer een debugger is verbonden). VmPolicy.Builder voegt detectoren toe voor lekken van Activity en Closable-objecten. Voor grote projecten (100+ schermen) wordt aanbevolen VmPolicy te configureren met penaltyDeath voor de detector Activity Leaks — dit is streng maar effectief.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
}
Gebruik voor automatische controle in CI/CD penaltyDeath — als een test een policy schendt, crasht de app met een uitzondering. Combineer dit met Android Test Orchestrator zodat elke test in een schoon proces wordt uitgevoerd. Schrijf voor UI-tests (Espresso, Compose Test) een aangepaste TestRule die StrictMode-schendingen opvangt en omzet in assertion-fouten. Voorbeeld: schakel StrictMode in @Before in en controleer in @After dat er geen violations zijn geweest.
Standaard is de drempel voor customSlowCall 2000 ms en voor disk_read en disk_write is er geen drempel (elke bewerking triggert). Via setSlowCallDurationThreshold en setSlowIoDurationThreshold kunt u eigen waarden in milliseconden instellen. Als uw app legitiem SharedPreferences op de hoofdthread leest (een kleine config), verhoog de drempel dan tot 10–20 ms — dit filtert snelle leesbewerkingen eruit, maar houdt trage.
StrictMode is een krachtige maar kieskeurige tool. Een verkeerde configuratie leidt tot miljoenen valse meldingen, waardoor ontwikkelaars er geen aandacht meer aan besteden. Hieronder volgen beproefde praktijken uit de ervaring van grote Android-teams.
Dit is een ijzeren regel: StrictMode mag NOOIT actief zijn in release-builds. Gebruik de vlag BuildConfig.DEBUG of een aangepaste buildConfigField. In release-builds voeren veel externe bibliotheken legitiem bewerkingen uit op de hoofdthread (SDK-initialisatie, cache-schrijven), en StrictMode zal valse meldingen genereren. Bovendien toont penaltyDialog in een release-build een dialoog aan de eindgebruiker — wat onacceptabel is.
Stel voor kleine projecten (1–10 schermen) penaltyLog in — logboeken zijn voldoende voor handmatige analyse. Voeg voor middelgrote projecten (10–50 schermen) penaltyDeath toe voor network en customSlowCalls. Schakel voor grote projecten (50+ schermen) de volledige set policies in met penaltyDeath in CI/CD, en penaltyLog voor lokale ontwikkeling. Deze gradatie overbelast de ontwikkelaar niet met valse crashes, maar bewaakt de kwaliteit in het pijplijn streng.
Sommige bibliotheken (Firebase, Crashlytics, Adjust) voeren legitiem bewerkingen op de achtergrond uit die StrictMode onterecht kan detecteren. Oplossingen: voeg de bibliotheek toe aan de whitelist via penaltyListener, werk de bibliotheek bij naar een versie met expliciete omschakeling naar een background thread, of gebruik StrictMode.vmPolicy. In Android 11+ is StrictMode.OnVmViolationListener beschikbaar voor programmatische filtering van schendingen op basis van de stacktrace.
// Filtering van false positives via penaltyListener
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyListener { violation ->
val stack = violation.stackTraceToString()
if ("com.google.firebase" !in stack) {
logViolation(violation)
}
}
.build()
)
StrictMode is niet de enige tool voor kwaliteitscontrole in het Android-ecosysteem. Om de plaats ervan te begrijpen, vergelijken we het met Android Lint, Android Profiler en Perfetto op basis van de belangrijkste criteria: controletijd, diepte van de analyse en automatisering.
| Criterium | StrictMode | Android Lint | Profiler / Perfetto |
|---|---|---|---|
| Controletijd | Runtime (tijdens het uitvoeren van de app) | Compile time (vóór de start) | Runtime (post-mortem) |
| Wat controleert het | Schijf, netwerk, lekken | XML, code, resources | CPU, geheugen, netwerk, energie |
| Automatisering | CI/CD via penaltyDeath | Gradle-taak + lint-baseline | Vereist handmatige analyse |
| Diepte | Alleen UI-thread en lekken | Statische codeanalyse | Volledig prestatiebeeld |
| Valse meldingen | Gemiddeld (afhankelijk van bibliotheken) | Laag (geconfigureerde regels) | Geen (feitelijke metingen) |
De beste strategie is om alle drie de benaderingen te combineren: Android Lint vangt duidelijke fouten op in de compilatiefase (bijvoorbeeld een vergeten IdleHandler), StrictMode detecteert problemen tijdens de runtime, en Android Profiler / Perfetto wordt gebruikt voor een diepgaande analyse wanneer de eerste twee tools geen antwoord geven. In echte projecten (Google Maps, Instagram) wordt StrictMode in de tweede ontwikkelingsweek ingevoerd — direct na het opzetten van de basisarchitectuur.
We bekijken twee reële scenario's waarin StrictMode helpt prestatieproblemen te detecteren en op te lossen: het lezen van SharedPreferences op de hoofdthread en een Activity-lek via een niet-opgeheven callback.
Bij het starten van de app detecteert StrictMode met het beleid detectDiskReads het lezen van SharedPreferences op de hoofdthread. Oplossing: laad de configuratie asynchroon via CoroutineScope of cache deze bij het starten in het geheugen. SharedPreferences leest synchroon een XML-bestand van de schijf — zelfs bij een klein bestand (1–2 KB) duurt de bewerking 1–5 ms, en op goedkope apparaten tot 20 ms, wat kan leiden tot een overgeslagen frame.
// ❌ Problematische code — SharedPrefs lezen in de UI-thread
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// StrictMode detectDiskReads → VIOLATION!
prefs = getSharedPreferences("config", MODE_PRIVATE)
}
}
// ✅ Gecorrigeerde code — lezen via Coroutine
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadConfigAsync()
}
}
StrictMode met VmPolicy.detectActivityLeaks detecteert een Activity die uit de stack is verwijderd (finish is aangeroepen), maar waarvan het Activity-object in het geheugen blijft hangen vanwege een statische referentie of een niet-opgeheven callback. Typisch scenario: EventBus of LocationListener registreren in onResume zonder de oproep unregister in onPause. VmPolicy geeft een stacktrace af met de regel waar de referentie is gemaakt.
// ❌ Lek — callback niet opgeheven
private var locationCallback: LocationCallback? = null
override fun onResume() {
super.onResume()
locationCallback = LocationCallback(this::onLocationUpdated)
locationManager.register(locationCallback) // StrictMode → LEAK!
}
override fun onPause() {
super.onPause()
// Vergeten: locationManager.unregister(locationCallback)
}
Veelgestelde vragen
StrictMode voegt inderdaad een kleine overhead toe — elke systeemoproep wordt gecontroleerd op naleving van de policies. De invloed op de prestaties is 1–3% in een debug-build en afwezig in release (waar StrictMode is uitgeschakeld). Bij het inschakelen van detectAll op oudere apparaten (Android 6–8) kan de overhead 5% bereiken, daarom wordt aanbevolen alleen de benodigde policies te configureren.
Ja, StrictMode is volledig compatibel met Jetpack Compose. De policies disk en network werken op het niveau van het framework, onafhankelijk van het UI-framework. Bovendien is in Compose de kritiek van UI-blokkades hoger — Compose tekent frames met 120 FPS op apparaten met een hoge verversingssnelheid, dus extra 5 ms voor het lezen van een bestand worden merkbaarder.
Vanaf Android 8.1 (API 27) kan SharedPreferences caching in het geheugen gebruiken — als het bestand al is gelezen, triggert een herhaalde lezing StrictMode niet. Controleer dat u getSharedPreferences voor de eerste keer aanroept (een koude lezing) en dat de policy detectDiskReads actief is. Controleer ook of StrictMode niet is overschreven in een parent-free fragment.
Gebruik in JUnit-tests StrictMode.allowThreadDiskReads() en StrictMode.allowThreadDiskWrites() in @Before, en herstel in @After de instellingen via StrictMode.enableDefaults(). Gebruik voor Instrumentation-tests een aangepaste TestRunner met tijdelijke opslag van de oorspronkelijke policy. In Espresso-tests is het handig om StrictMode-gevoelige code in een IdlingResource te wrappen.
StrictMode werkt alleen op het Android-platform via de Android SDK. In Kotlin Multiplatform (KMP) kan code in commonMain geen StrictMode gebruiken, maar voor androidMain kunt u het zoals gebruikelijk toevoegen. Gebruik voor het iOS-gedeelte het equivalent — de DispatchQueue.main.async assertion voor de hoofdthread.
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