StrictMode: co to jest, tryb ścisłych reguł i debugowanie w Androidzie

Autor: IT Sectr Opublikowano: 2026-03-31 Czas czytania: 8 min

StrictMode to wbudowane w Android SDK narzędzie deweloperskie, które w czasie rzeczywistym wykrywa i informuje o przypadkowych operacjach wejścia-wyjścia oraz wywołaniach sieciowych w głównym wątku aplikacji. Nie naprawia błędów, a działa jako detektor — wyrzuca wyjątki lub zapisuje do LogCat przy naruszeniu zadanych polityk. Według Google, 2024, prawidłowa konfiguracja StrictMode pozwala wykryć do 80% problemów wydajnościowych jeszcze przed premierą aplikacji.

Najważniejsze

  • StrictMode — detektor naruszeń wydajności w głównym wątku Androida
  • Polityki dysku (disk_read, disk_write) i sieci (network) stanowią podstawowy zestaw kontroli
  • Narzędzie nie naprawia problemów, a powiadamia o nich przez LogCat, dialog lub crash
  • Konfiguracja wykonuje się w Application.onCreate i używa setThreadPolicy + setVmPolicy
  • Tryby penalty: wyrzucenie wyjątku (death), logowanie, powiadomienie w dropbox

Co to jest StrictMode

StrictMode to API wchodzące w skład Android SDK od API Level 9 (Android 2.3 Gingerbread). Jego zadaniem jest wykrywanie w czasie rzeczywistym przypadkowego wykonywania ciężkich operacji w głównym (UI) wątku, które mogą zablokować renderowanie interfejsu. Główny wątek odpowiada za przetwarzanie danych wejściowych użytkownika, obliczanie układu i renderowanie — każde zablokowanie dłuższe niż 16 ms prowadzi do pominięcia klatki.

Filozofia narzędzia

StrictMode kieruje się zasadą „fail fast” — wykryj problem jak najwcześniej, najlepiej w momencie jego pierwszego pojawienia się. Zamiast czekać na skargi użytkowników dotyczące spowolnień, deweloper otrzymuje sygnał (logi, dialog lub crash) już na etapie rozwoju. Narzędzie nie wymaga dodatkowych bibliotek ani konfiguracji Gradle — wystarczy kilka linijek kodu w Application.onCreate, a działa ono automatycznie na wszystkich urządzeniach.

Grupa docelowa

StrictMode jest przeznaczony dla wszystkich deweloperów Androida, niezależnie od doświadczenia. Początkującym pomaga wyrobić prawidłowe nawyki (nie wykonywać zapytań sieciowych w wątku UI), doświadczonym — automatyzować kontrolę jakości w CI/CD pipeline. Duże projekty (Google, Uber, Spotify) włączają StrictMode w debug builds z penaltyDeath, a w wydaniowych buildach wyłączają przez sprawdzenie BuildConfig.DEBUG.

Jak działa StrictMode

StrictMode przechwytuje wywołania systemowe, które mogą blokować wątek, i porównuje je z zestawem aktywnych polityk. Jeśli wywołanie odpowiada polityce i jest wykonywane w głównym wątku, StrictMode stosuje zadany penalty (karę). Mechanizm przechwytywania jest zaimplementowany przez wewnątrzprocesowy hook — nie używa refleksji i działa z minimalnym narzutem.

Mechanizm detekcji

Przy aktywacji polityki StrictMode wstawia swój handler w punkt wejścia wywołań systemowych (FileInputStream, FileOutputStream, Socket, URLConnection). Gdy aplikacja wywołuje, na przykład, URLConnection.openStream w głównym wątku, StrictMode sprawdza bieżący wątek — jeśli jest to main thread, narzędzie się uruchamia. W Android 6.0+ mechanizm został wzmocniony: wywołania sieciowe w main thread generują NetworkOnMainThreadException nawet bez StrictMode, ale StrictMode pozwala kontrolować także dyskowe I/O.

Penalty (kara)

Każda polityka może mieć swój typ penalty lub kombinację: penaltyLog — zapis do LogCat ze stacktrace, penaltyDialog — pokazanie dialogu użytkownikowi (tylko w debug), penaltyDeath — wyrzucenie wyjątku i crash aplikacji, penaltyDropBox — zapisanie danych w DropBoxManager do późniejszej analizy. Dla CI/CD pipeline zaleca się penaltyDeath — gwarantuje to, że żaden merge z naruszeniem nie przejdzie niezauważony.

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()
                    .penaltyLog()
                    .penaltyDeath()
                    .build()
            )
        }
    }
}

Polityki StrictMode

StrictMode dzieli polityki na dwa poziomy: ThreadPolicy (wątkowe — czego nie robić w głównym wątku) i VmPolicy (maszyny wirtualnej — wycieki pamięci i zasobów). Oba poziomy konfiguruje się niezależnie i działają równolegle.

ThreadPolicy: dysk i sieć

Na poziomie wątku StrictMode kontroluje cztery typy naruszeń: odczyt z dysku (detectDiskReads), zapis na dysk (detectDiskWrites), operacje sieciowe (detectNetwork) i niestandardowe wolne wywołania (detectCustomSlowCalls). disk_read uruchamia się przy każdym odczycie SharedPreferences, SQLite, plików w głównym wątku. network — przy żądaniach HTTP, WebSocket, połączeniach Socket. W Android 11+ dodano detectUnbufferedIO do wykrywania niebuforowanego wejścia-wyjścia.

VmPolicy: wycieki pamięci

VmPolicy kontroluje wycieki na poziomie maszyny wirtualnej ART: detectActivityLeaks (Activities, które nie zostały zniszczone), detectLeakedClosableObjects (niezamknięte Cursor, Stream, Socket), detectLeakedRegistrationObjects (nieodwołane BroadcastReceiver, ServiceConnection). Jeśli VmPolicy wykryje, że Activity została utworzona, ale nie zniszczona po wywołaniu onDestroy, wypisuje pełny stack trace — to oszczędza godziny debugowania wycieków pamięci.

PolitykaPoziomCo wykrywa
detectDiskReadsThreadOdczyt SharedPrefs, SQLite, plików w wątku UI
detectDiskWritesThreadZapis do SharedPrefs, SQLite, plików w wątku UI
detectNetworkThreadWszelkie operacje sieciowe w wątku UI
detectActivityLeaksVMActivities, które przetrwały onDestroy
detectLeakedClosableObjectsVMNiezamknięte Cursor, Stream, Socket

Niestandardowe etykiety (customSlowCall)

Przez detectCustomSlowCalls można oznaczyć własne metody jako „podejrzane” i otrzymywać ostrzeżenie przy przekroczeniu zadanego progu. Na przykład, jeśli twoja metoda loadUserProfile() zwykle wykonuje się 5 ms, ale w niektórych przypadkach zajmuje 200 ms — opakuj ją w StrictMode.noteSlowCall("loadUserProfile"). Jeśli czas trwania przekroczy próg (domyślnie 2000 ms), StrictMode wygeneruje penalty. Próg konfiguruje się przez setSlowCallDurationThreshold.

Jak skonfigurować StrictMode

Podstawowa konfiguracja StrictMode zajmuje 10 linijek kodu i wykonuje się w metodzie onCreate niestandardowej klasy Application. Główna zasada: StrictMode włącza się tylko w debug buildach — w release buildach spowalnia aplikację i może generować fałszywe alarmy.

Podstawowa konfiguracja

Utwórz klasę dziedziczącą po Application, zarejestruj ją w AndroidManifest.xml przez atrybut android:name i dodaj konfigurację StrictMode. ThreadPolicy.Builder włącza wszystkie detektory i wszystkie rodzaje penalty (oprócz dialog — działa tylko przy podłączonym debuggerze). VmPolicy.Builder dodaje detektory wycieków Activity i Closable. Dla dużych projektów (100+ ekranów) zaleca się skonfigurowanie VmPolicy z penaltyDeath na detektor Activity Leaks — to surowe, ale skuteczne.

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            StrictMode.setVmPolicy(
                StrictMode.VmPolicy.Builder()
                    .detectActivityLeaks()
                    .detectLeakedClosableObjects()
                    .detectLeakedRegistrationObjects()
                    .penaltyLog()
                    .penaltyDeath()
                    .build()
            )
        }
    }
}

Integracja w CI/CD

Do automatycznej kontroli w CI/CD używaj penaltyDeath — jeśli jakiś test naruszy politykę, aplikacja padnie z wyjątkiem. Łącz z Android Test Orchestrator, aby każdy test uruchamiał się w czystym procesie. Dla testów UI (Espresso, Compose Test) napisz niestandardowy TestRule, który przechwytuje naruszenia StrictMode i zamienia je w assertion failure. Przykład: w @Before włącz StrictMode, a w @After sprawdź, czy nie było violations.

Konfiguracja progów

Domyślnie próg dla customSlowCall wynosi 2000 ms, dla disk_read i disk_write — bez progu (każda operacja go wyzwala). Przez setSlowCallDurationThreshold i setSlowIoDurationThreshold można ustawić własne wartości w milisekundach. Jeśli twoja aplikacja legalnie odczytuje SharedPreferences w głównym wątku (mała konfiguracja), zwiększ próg do 10–20 ms — to odetnie szybkie odczyty, ale pozostawi wolne.

Najlepsze praktyki StrictMode

StrictMode to potężne, ale kapryśne narzędzie. Nieprawidłowa konfiguracja prowadzi do miliona fałszywych alarmów, przez co deweloperzy przestają na nie zwracać uwagę. Poniżej — sprawdzone praktyki zebrane z doświadczenia dużych zespołów Android.

Włączaj tylko w debug buildach

To żelazna zasada: StrictMode NIGDY nie powinien być aktywny w release buildach. Używaj flagi BuildConfig.DEBUG lub niestandardowej buildConfigField. W release buildach wiele bibliotek zewnętrznych legalnie wykonuje operacje w głównym wątku (inicjalizacja SDK, zapis cache), a StrictMode wygeneruje fałszywe alarmy. Co więcej, penaltyDialog w release buildzie pokaże dialog użytkownikowi końcowemu — co jest niedopuszczalne.

Używaj trzech poziomów rygorystyczności

Dla małych projektów (1–10 ekranów) skonfiguruj penaltyLog — wystarczy logów do ręcznej analizy. Dla średnich projektów (10–50 ekranów) dodaj penaltyDeath dla network i customSlowCalls. Dla dużych projektów (50+ ekranów) włącz pełny zestaw polityk z penaltyDeath w CI/CD, a do lokalnego rozwoju — penaltyLog. Taka gradacja pozwala nie przeciążać dewelopera fałszywymi crashami, ale surowo kontrolować jakość w pipeline.

Obsługuj fałszywe alarmy

Niektóre biblioteki (Firebase, Crashlytics, Adjust) legalnie wykonują operacje w tle, które StrictMode może błędnie wykryć. Rozwiązania: dodaj bibliotekę do whitelist przez penaltyListener, zaktualizuj bibliotekę do wersji z jawnym przełączaniem na background thread lub użyj StrictMode.vmPolicy. W Android 11+ pojawił się StrictMode.OnVmViolationListener do programowego filtrowania naruszeń według stacktrace.

kotlin
// Filtracja fałszywych pozytywów przez penaltyListener
StrictMode.setThreadPolicy(
    StrictMode.ThreadPolicy.Builder()
        .detectAll()
        .penaltyListener { violation ->
            val stack = violation.stackTraceToString()
            if ("com.google.firebase" !in stack) {
                logViolation(violation)
            }
        }
        .build()
)

StrictMode vs Android Lint vs profilery

StrictMode nie jest jedynym narzędziem kontroli jakości w ekosystemie Android. Aby zrozumieć jego miejsce, porównajmy go z Android Lint, Android Profiler i Perfetto według kluczowych kryteriów: czas sprawdzania, głębokość analizy i automatyzacja.

KryteriumStrictModeAndroid LintProfiler / Perfetto
Czas sprawdzaniaRuntime (podczas działania aplikacji)Compile time (przed uruchomieniem)Runtime (post-mortem)
Co sprawdzaDysk, sieć, wyciekiXML, kod, zasobyCPU, pamięć, sieć, energia
AutomatyzacjaCI/CD przez penaltyDeathGradle task + lint-baselineWymaga ręcznej analizy
GłębokośćTylko UI-wątek i wyciekiStatyczna analiza koduPełny obraz wydajności
Fałszywe alarmyŚrednie (zależą od bibliotek)Niskie (skonfigurowane reguły)Brak (rzeczywiste pomiary)

Najlepsza strategia to łączenie wszystkich trzech podejść: Android Lint łapie oczywiste błędy na etapie kompilacji (na przykład zapomniany IdleHandler), StrictMode wykrywa problemy w czasie rzeczywistym, a Android Profiler / Perfetto jest używany do głębokiej analizy, gdy pierwsze dwa narzędzia nie dają odpowiedzi. W rzeczywistych projektach (Google Maps, Instagram) StrictMode wdraża się w drugim tygodniu rozwoju — zaraz po skonfigurowaniu podstawowej architektury.

Przykłady kodu ze StrictMode

Rozpatrzmy dwa rzeczywiste scenariusze, w których StrictMode pomaga wykryć i rozwiązać problemy wydajnościowe: odczyt SharedPreferences w głównym wątku i wyciek Activity przez niezarejestrowany callback.

Detekcja powolnego SharedPreferences

Przy starcie aplikacji StrictMode z polityką detectDiskReads wykryje odczyt SharedPreferences w głównym wątku. Rozwiązanie: ładować konfigurację asynchronicznie przez CoroutineScope lub buforować w pamięci przy starcie. SharedPreferences synchronicznie odczytuje plik XML z dysku — nawet przy małym pliku (1–2 KB) operacja zajmuje 1–5 ms, a na tanich urządzeniach do 20 ms, co może prowadzić do pominięcia klatki.

kotlin
// ❌ Problemowy kod — odczyt SharedPrefs w wątku UI
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // StrictMode detectDiskReads → VIOLATION!
        prefs = getSharedPreferences("config", MODE_PRIVATE)
    }
}

// ✅ Poprawiony kod — odczyt przez Coroutine
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        loadConfigAsync()
    }
}

Wykrywanie wycieku Activity

StrictMode z VmPolicy.detectActivityLeaks wykryje Activity, która wyszła ze stosu (finish wywołany), ale obiekt Activity nadal wisi w pamięci z powodu statycznego odniesienia lub niezarejestrowanego callbacka. Typowy scenariusz: rejestracja EventBus lub LocationListener w onResume bez wywołania unregister w onPause. VmPolicy wypisze stacktrace ze wskazaniem linii, w której utworzono odniesienie.

kotlin
// ❌ Wyciek — callback nie został anulowany
private var locationCallback: LocationCallback? = null

override fun onResume() {
    super.onResume()
    locationCallback = LocationCallback(this::onLocationUpdated)
    locationManager.register(locationCallback) // StrictMode → LEAK!
}

override fun onPause() {
    super.onPause()
    // Zapomniano: locationManager.unregister(locationCallback)
}

Często zadawane pytania

Czy StrictMode spowalnia aplikację?

StrictMode rzeczywiście dodaje niewielki narzut — każde wywołanie systemowe jest sprawdzane pod kątem zgodności z politykami. Wpływ na wydajność wynosi 1–3% w debug buildzie i nie występuje w release (gdzie StrictMode jest wyłączony). Przy włączeniu detectAll na starych urządzeniach (Android 6–8) narzut może sięgać 5%, dlatego zaleca się konfigurować tylko potrzebne polityki.

Czy można używać StrictMode z Jetpack Compose?

Tak, StrictMode jest w pełni kompatybilny z Jetpack Compose. Polityki disk i network działają na poziomie frameworka, niezależnie od frameworka UI. Co więcej, w Compose krytyczność blokad UI jest wyższa — Compose przerysowuje klatki z częstotliwością 120 FPS na urządzeniach z wysoką częstotliwością odświeżania, dlatego dodatkowe 5 ms na odczyt pliku stają się bardziej zauważalne.

Dlaczego StrictMode nie działa przy odczycie SharedPreferences?

Począwszy od Android 8.1 (API 27), SharedPreferences może używać buforowania w pamięci — jeśli plik został już odczytany, ponowny odczyt nie wyzwala StrictMode. Sprawdź, czy wywołujesz getSharedPreferences po raz pierwszy (zimny odczyt) i czy polityka detectDiskReads jest aktywna. Sprawdź także, czy StrictMode nie jest nadpisywany w fragmencie parent-free.

Jak wyłączyć StrictMode dla poszczególnych testów?

W testach JUnit używaj StrictMode.allowThreadDiskReads() i StrictMode.allowThreadDiskWrites() w @Before, a w @After przywróć ustawienia przez StrictMode.enableDefaults(). Dla testów Instrumentation używaj niestandardowego TestRunnera z tymczasowym zapisaniem oryginalnej polityki. W testach Espresso wygodnie jest opakować kod podatny na StrictMode w IdlingResource.

Czy StrictMode jest potrzebny w Kotlin Multiplatform?

StrictMode działa tylko na platformie Android przez Android SDK. W Kotlin Multiplatform (KMP) kod commonMain nie może używać StrictMode, ale dla androidMain możesz dodać go jak zwykle. Dla części iOS użyj odpowiednika — DispatchQueue.main.async assertion dla głównego wątku.

Podsumowanie

  • StrictMode — detektor czasu rzeczywistego problemów wydajności w głównym wątku Androida
  • Polityki dzielą się na ThreadPolicy (dysk, sieć) i VmPolicy (wycieki pamięci)
  • Konfiguracja zajmuje 10 linijek kodu w Application.onCreate ze sprawdzeniem BuildConfig.DEBUG
  • Dla CI/CD używaj penaltyDeath — naruszenie polityki prowadzi do upadku aplikacji
  • StrictMode nie zastępuje, a uzupełnia Android Lint i Perfetto
  • Prawidłowa filtracja fałszywych alarmów to klucz do efektywnego użycia narzędzia
  • Zaleca się wdrażać StrictMode w drugim tygodniu rozwoju projektu

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również