StrictMode este un instrument de dezvoltare integrat în Android SDK care detectează în timp real și raportează operațiile aleatoare de intrare-ieșire și apelurile de rețea pe firul principal al aplicației. Nu corectează erorile, ci acționează ca un detector — aruncă excepții sau scrie în LogCat la încălcarea politicilor stabilite. Potrivit Google, 2024, configurarea corectă a StrictMode permite detectarea a până la 80% din problemele de performanță înainte de lansarea aplicației.
Principalele Puncte
StrictMode este o API inclusă în Android SDK începând cu API Level 9 (Android 2.3 Gingerbread). Sarcina sa este de a detecta în timp real executarea accidentală a operațiilor grele pe firul principal (UI) care pot bloca randarea interfeței. Firul principal este responsabil pentru procesarea intrărilor utilizatorului, calcularea layout-ului și randare — orice blocare mai lungă de 16 ms duce la omiterea cadrelor.
StrictMode urmează principiul „fail fast” — detectează problema cât mai devreme posibil, ideal în momentul primei sale apariții. În loc să aștepte plângerile utilizatorilor privind încetinirile, dezvoltatorul primește un semnal (loguri, dialog sau crash) direct în faza de dezvoltare. Instrumentul nu necesită biblioteci suplimentare sau configurare Gradle — sunt suficiente câteva linii de cod în Application.onCreate și funcționează automat pe toate dispozitivele.
StrictMode este destinat tuturor dezvoltatorilor Android, indiferent de experiență. Începătorilor îi ajută să formeze obiceiuri corecte (să nu facă solicitări de rețea în firul UI), iar celor experimentați — să automatizeze controlul calității în pipeline-ul CI/CD. Proiectele mari (Google, Uber, Spotify) activează StrictMode în debug builds cu penaltyDeath, iar în release builds îl dezactivează prin verificarea BuildConfig.DEBUG.
StrictMode interceptează apelurile de sistem care pot bloca firul de execuție și le compară cu setul de politici active. Dacă apelul corespunde unei politici și este executat pe firul principal, StrictMode aplică penalty-ul stabilit. Mecanismul de interceptare este implementat printr-un hook intra-proces — nu folosește reflection și funcționează cu un overhead minim.
La activarea politicii, StrictMode își plasează handlerul în punctul de intrare al apelurilor de sistem (FileInputStream, FileOutputStream, Socket, URLConnection). Când aplicația apelează, de exemplu, URLConnection.openStream pe firul principal, StrictMode verifică firul curent — dacă este main thread, instrumentul se activează. În Android 6.0+ mecanismul a fost întărit: apelurile de rețea în main thread generează NetworkOnMainThreadException chiar și fără StrictMode, dar StrictMode permite controlul și al I/O-ului pe disc.
Fiecare politică poate avea propriul tip de penalty sau o combinație: penaltyLog — scriere în LogCat cu stacktrace, penaltyDialog — afișarea unui dialog utilizatorului (doar în debug), penaltyDeath — aruncarea unei excepții și crash-ul aplicației, penaltyDropBox — salvarea datelor în DropBoxManager pentru analiză ulterioară. Pentru pipeline-ul CI/CD se recomandă penaltyDeath — garantează că niciun merge cu încălcări nu va trece neobservat.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
}
StrictMode împarte politicile pe două niveluri: ThreadPolicy (de fir — ce să nu se facă pe firul principal) și VmPolicy (mașină virtuală — scurgeri de memorie și resurse). Ambele niveluri se configurează independent și funcționează în paralel.
La nivel de fir, StrictMode controlează patru tipuri de încălcări: citirea de pe disc (detectDiskReads), scrierea pe disc (detectDiskWrites), operațiile de rețea (detectNetwork) și apelurile lente personalizate (detectCustomSlowCalls). disk_read se declanșează la orice citire SharedPreferences, SQLite, fișiere pe firul principal. network — la cereri HTTP, WebSocket, conexiuni Socket. În Android 11+ a fost adăugat detectUnbufferedIO pentru detectarea I/O-ului fără buffer.
VmPolicy controlează scurgerile la nivelul mașinii virtuale ART: detectActivityLeaks (Activități care nu au fost distruse), detectLeakedClosableObjects (Cursor, Stream, Socket neînchise), detectLeakedRegistrationObjects (BroadcastReceiver, ServiceConnection neanulate). Dacă VmPolicy detectează că o Activitate a fost creată dar nu distrusă după apelul onDestroy, afișează stack trace-ul complet — economisește ore de depanare a scurgerilor de memorie.
| Politica | Nivel | Ce detectează |
|---|---|---|
| detectDiskReads | Thread | Citire SharedPrefs, SQLite, fișiere în firul UI |
| detectDiskWrites | Thread | Scriere în SharedPrefs, SQLite, fișiere în firul UI |
| detectNetwork | Thread | Orice operații de rețea în firul UI |
| detectActivityLeaks | VM | Activități care au supraviețuit onDestroy |
| detectLeakedClosableObjects | VM | Cursor, Stream, Socket neînchise |
Prin detectCustomSlowCalls puteți marca propriile metode ca „sospicioase” și primiți avertismente la depășirea unui prag stabilit. De exemplu, dacă metoda dvs. loadUserProfile() se execută de obicei în 5 ms, dar în unele cazuri durează 200 ms — înfășurați-o în StrictMode.noteSlowCall("loadUserProfile"). Dacă durata depășește pragul (implicit 2000 ms), StrictMode va genera un penalty. Pragul se configurează prin setSlowCallDurationThreshold.
Configurarea de bază StrictMode ocupă 10 linii de cod și se realizează în metoda onCreate a unei clase Application personalizate. Regula principală: StrictMode se activează doar în debug builds — în release builds încetinește aplicația și poate genera alarme false.
Creați o clasă care extinde Application, înregistrați-o în AndroidManifest.xml prin atributul android:name și adăugați configurarea StrictMode. ThreadPolicy.Builder activează toți detectorii și toate tipurile de penalty (cu excepția dialog — funcționează doar cu debuggerul conectat). VmPolicy.Builder adaugă detectori de scurgeri Activity și Closable. Pentru proiecte mari (100+ ecrane) se recomandă configurarea VmPolicy cu penaltyDeath pe detectorul Activity Leaks — este strict, dar eficient.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
}
Pentru controlul automat în CI/CD utilizați penaltyDeath — dacă vreun test încalcă politica, aplicația va crasa cu o excepție. Combinați cu Android Test Orchestrator pentru ca fiecare test să ruleze într-un proces curat. Pentru testele UI (Espresso, Compose Test) scrieți un TestRule personalizat care interceptează încălcările StrictMode și le transformă în assertion failure. Exemplu: în @Before activați StrictMode, iar în @After verificați dacă nu au fost violations.
Implicit, pragul pentru customSlowCall este de 2000 ms, iar pentru disk_read și disk_write — fără prag (orice operație îl declanșează). Prin setSlowCallDurationThreshold și setSlowIoDurationThreshold puteți seta propriile valori în milisecunde. Dacă aplicația dvs. citește legitim SharedPreferences pe firul principal (configurare mică), măriți pragul la 10–20 ms — va tăia citirile rapide, dar le va păstra pe cele lente.
StrictMode este un instrument puternic, dar capricios. Configurarea incorectă duce la un milion de alarme false, din cauza cărora dezvoltatorii încetează să le mai acorde atenție. Mai jos sunt practici verificate, colectate din experiența echipelor mari Android.
Aceasta este o regulă de fier: StrictMode NU trebuie să fie activ NICIODATĂ în release builds. Folosiți flag-ul BuildConfig.DEBUG sau un buildConfigField personalizat. În release builds, multe biblioteci terțe execută legitim operații pe firul principal (inițializare SDK, scriere cache), iar StrictMode va genera alarme false. Mai mult, penaltyDialog în release build va afișa un dialog utilizatorului final — ceea ce este inacceptabil.
Pentru proiecte mici (1–10 ecrane) configurați penaltyLog — logurile sunt suficiente pentru analiza manuală. Pentru proiecte medii (10–50 ecrane) adăugați penaltyDeath pentru network și customSlowCalls. Pentru proiecte mari (50+ ecrane) activați setul complet de politici cu penaltyDeath în CI/CD, iar pentru dezvoltare locală — penaltyLog. Această gradare permite să nu supraîncărcați dezvoltatorul cu crash-uri false, dar să controlați strict calitatea în pipeline.
Unele biblioteci (Firebase, Crashlytics, Adjust) execută legitim operații în fundal pe care StrictMode le poate detecta eronat. Soluții: adăugați biblioteca în whitelist prin penaltyListener, actualizați biblioteca la o versiune cu comutare explicită pe background thread sau folosiți StrictMode.vmPolicy. În Android 11+ a apărut StrictMode.OnVmViolationListener pentru filtrarea programatică a încălcărilor după stacktrace.
// Filtrarea alarmelor false prin penaltyListener
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyListener { violation ->
val stack = violation.stackTraceToString()
if ("com.google.firebase" !in stack) {
logViolation(violation)
}
}
.build()
)
StrictMode nu este singurul instrument de control al calității în ecosistemul Android. Pentru a înțelege locul său, să-l comparăm cu Android Lint, Android Profiler și Perfetto după criterii cheie: timpul de verificare, adâncimea analizei și automatizarea.
| Criteriu | StrictMode | Android Lint | Profiler / Perfetto |
|---|---|---|---|
| Timp verificare | Runtime (în timpul funcționării) | Compile time (înainte de lansare) | Runtime (post-mortem) |
| Ce verifică | Disc, rețea, scurgeri | XML, cod, resurse | CPU, memorie, rețea, energie |
| Automatizare | CI/CD prin penaltyDeath | Gradle task + lint-baseline | Necesită analiză manuală |
| Adâncime | Doar firul UI și scurgeri | Analiză statică de cod | Imagine completă a performanței |
| Alarme false | Medii (depind de biblioteci) | Scăzute (reguli configurate) | Nu (măsurători reale) |
Cea mai bună strategie este combinarea tuturor celor trei abordări: Android Lint prinde erorile evidente la compilare (de exemplu, un IdleHandler uitat), StrictMode detectează problemele în runtime, iar Android Profiler / Perfetto este utilizat pentru analiza aprofundată când primele două instrumente nu oferă răspunsuri. În proiecte reale (Google Maps, Instagram), StrictMode este implementat în a doua săptămână de dezvoltare — imediat după configurarea arhitecturii de bază.
Să analizăm două scenarii reale în care StrictMode ajută la detectarea și remedierea problemelor de performanță: citirea SharedPreferences pe firul principal și scurgerea Activity printr-un callback neinregistrat.
La pornirea aplicației, StrictMode cu politica detectDiskReads va detecta citirea SharedPreferences pe firul principal. Soluția: încărcați configurația asincron prin CoroutineScope sau cache-uiți în memorie la pornire. SharedPreferences citește sincron fișierul XML de pe disc — chiar și la un fișier mic (1–2 KB), operația durează 1–5 ms, iar pe dispozitive ieftine până la 20 ms, ceea ce poate duce la omiterea cadrelor.
// ❌ Cod problematic — citire SharedPrefs în firul UI
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// StrictMode detectDiskReads → VIOLATION!
prefs = getSharedPreferences("config", MODE_PRIVATE)
}
}
// ✅ Cod corectat — citire prin Coroutine
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadConfigAsync()
}
}
StrictMode cu VmPolicy.detectActivityLeaks va detecta o Activitate care a ieșit din stivă (finish apelat), dar obiectul Activity continuă să existe în memorie din cauza unei referințe statice sau a unui callback neanulat. Scenariu tipic: înregistrarea EventBus sau LocationListener în onResume fără a apela unregister în onPause. VmPolicy va afișa stack trace-ul cu indicarea liniei unde a fost creată referința.
// ❌ Scurgere — callback neanulat
private var locationCallback: LocationCallback? = null
override fun onResume() {
super.onResume()
locationCallback = LocationCallback(this::onLocationUpdated)
locationManager.register(locationCallback) // StrictMode → LEAK!
}
override fun onPause() {
super.onPause()
// Uitat: locationManager.unregister(locationCallback)
}
Întrebări frecvente
StrictMode adaugă într-adevăr un mic overhead — fiecare apel de sistem este verificat pentru conformitate cu politicile. Impactul asupra performanței este de 1–3% în debug build și absent în release (unde StrictMode este dezactivat). La activarea detectAll pe dispozitive vechi (Android 6–8), overhead-ul poate ajunge la 5%, de aceea se recomandă configurarea doar a politicilor necesare.
Da, StrictMode este complet compatibil cu Jetpack Compose. Politicile disk și network funcționează la nivel de framework, independent de framework-ul UI. Mai mult, în Compose criticitatea blocărilor UI este mai mare — Compose redesenează cadrele la 120 FPS pe dispozitivele cu rată mare de reîmprospătare, de aceea 5 ms suplimentare pentru citirea unui fișier devin mai vizibile.
Începând cu Android 8.1 (API 27), SharedPreferences poate folosi cache în memorie — dacă fișierul a fost deja citit, citirea repetată nu declanșează StrictMode. Verificați că apelați getSharedPreferences pentru prima dată (citire la rece) și că politica detectDiskReads este activă. Verificați, de asemenea, dacă StrictMode nu este suprascris într-un fragment parent-free.
În teste JUnit, utilizați StrictMode.allowThreadDiskReads() și StrictMode.allowThreadDiskWrites() în @Before, iar în @After restaurați setările prin StrictMode.enableDefaults(). Pentru teste Instrumentation, utilizați un TestRunner personalizat cu salvarea temporară a politicii originale. În teste Espresso, este convenabil să înfășurați codul sensibil la StrictMode într-un IdlingResource.
StrictMode funcționează doar pe platforma Android prin Android SDK. În Kotlin Multiplatform (KMP), codul commonMain nu poate folosi StrictMode, dar pentru androidMain îl puteți adăuga ca de obicei. Pentru partea iOS, utilizați analogul — DispatchQueue.main.async assertion pentru firul principal.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și