StrictMode é uma ferramenta de desenvolvedor incorporada ao Android SDK que detecta e relata em tempo real operações acidentais de E/S e chamadas de rede na thread principal do aplicativo. Ela não corrige erros, mas atua como um detector — lança exceções ou escreve no LogCat quando as políticas configuradas são violadas. De acordo com Google, 2024, a configuração adequada do StrictMode pode detectar até 80% dos problemas de desempenho antes do lançamento do aplicativo.
Principais conclusões
StrictMode é uma API incluída no Android SDK desde o API Level 9 (Android 2.3 Gingerbread). Sua tarefa é detectar em tempo de execução a execução acidental de operações pesadas na thread principal (UI) que poderiam bloquear a renderização da interface. A thread principal lida com o processamento de entrada do usuário, cálculo de layout e renderização — qualquer bloqueio superior a 16 ms resulta em queda de quadro.
StrictMode segue o princípio de “falhar rápido” — detectar o problema o mais cedo possível, idealmente no momento de sua primeira aparição. Em vez de esperar reclamações de usuários sobre lentidão, o desenvolvedor recebe um sinal (logs, diálogo ou crash) diretamente na fase de desenvolvimento. A ferramenta não requer bibliotecas adicionais ou configuração do Gradle — apenas algumas linhas de código no Application.onCreate, e funciona automaticamente em todos os dispositivos.
StrictMode é projetado para todos os desenvolvedores Android, independentemente da experiência. Para iniciantes, ajuda a formar bons hábitos (não fazer requisições de rede na thread de UI); para desenvolvedores experientes, automatiza o controle de qualidade no pipeline CI/CD. Grandes projetos (Google, Uber, Spotify) incluem StrictMode em builds de depuração com penaltyDeath, e o desativam em builds de lançamento através da verificação BuildConfig.DEBUG.
StrictMode intercepta chamadas de sistema que poderiam bloquear a thread e as compara com o conjunto de políticas ativas. Se uma chamada corresponde a uma política e é executada na thread principal, o StrictMode aplica a penalidade especificada. O mecanismo de interceptação é implementado através de um hook dentro do processo — não usa reflexão e opera com sobrecarga mínima.
Quando a política do StrictMode é ativada, ele injeta seu manipulador nos pontos de entrada das chamadas de sistema (FileInputStream, FileOutputStream, Socket, URLConnection). Quando o aplicativo chama, por exemplo, URLConnection.openStream na thread principal, o StrictMode verifica a thread atual — se for a thread principal, a ferramenta é acionada. No Android 6.0+, o mecanismo é aprimorado: chamadas de rede na thread principal geram NetworkOnMainThreadException mesmo sem StrictMode, mas o StrictMode também permite controlar E/S de disco.
Cada política pode ter seu próprio tipo de penalidade ou combinação: penaltyLog — escreve no LogCat com stack trace, penaltyDialog — mostra um diálogo ao usuário (apenas debug), penaltyDeath — lança uma exceção e causa crash no aplicativo, penaltyDropBox — salva dados no DropBoxManager para análise posterior. Para pipelines CI/CD, penaltyDeath é recomendado — garante que nenhum merge com violações passe despercebido.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
}
StrictMode divide as políticas em dois níveis: ThreadPolicy (nível de thread — o que não pode ser feito na thread principal) e VmPolicy (máquina virtual — vazamentos de memória e recursos). Ambos os níveis são configurados independentemente e funcionam em paralelo.
No nível de thread, o StrictMode controla quatro tipos de violações: leituras de disco (detectDiskReads), escritas em disco (detectDiskWrites), operações de rede (detectNetwork) e chamadas lentas personalizadas (detectCustomSlowCalls). disk_read é acionado em qualquer leitura de SharedPreferences, SQLite ou arquivos na thread principal. network é acionado em requisições HTTP, WebSocket e conexões Socket. No Android 11+, foi adicionado detectUnbufferedIO para detectar E/S sem buffer.
VmPolicy controla vazamentos no nível da máquina virtual ART: detectActivityLeaks (atividades que não foram destruídas), detectLeakedClosableObjects (Cursor, Stream, Socket não fechados), detectLeakedRegistrationObjects (BroadcastReceiver, ServiceConnection não registrados). Se VmPolicy detectar que uma Activity foi criada mas não destruída após chamar onDestroy, ele exibe um stack trace completo — economizando horas de depuração de vazamentos de memória.
| Política | Nível | O que detecta |
|---|---|---|
| detectDiskReads | Thread | Leitura de SharedPrefs, SQLite, arquivos na thread de UI |
| detectDiskWrites | Thread | Escrita em SharedPrefs, SQLite, arquivos na thread de UI |
| detectNetwork | Thread | Qualquer operação de rede na thread de UI |
| detectActivityLeaks | VM | Activities que sobrevivem ao onDestroy |
| detectLeakedClosableObjects | VM | Cursor, Stream, Socket não fechados |
Através de detectCustomSlowCalls, você pode marcar seus próprios métodos como “suspeitos” e receber um aviso quando um limite especificado for excedido. Por exemplo, se seu método loadUserProfile() normalmente leva 5 ms mas às vezes leva 200 ms — envolva-o em StrictMode.noteSlowCall(“loadUserProfile”). Se a duração exceder o limite (padrão 2000 ms), o StrictMode gerará uma penalidade. O limite é configurado através de setSlowCallDurationThreshold.
A configuração básica do StrictMode leva 10 linhas de código e é feita no método onCreate de uma classe Application personalizada. A regra principal: StrictMode é ativado apenas em builds de depuração — em builds de lançamento ele diminui a velocidade do aplicativo e pode criar falsos positivos.
Crie uma classe que estenda Application, registre-a no AndroidManifest.xml através do atributo android:name e adicione a configuração do StrictMode. ThreadPolicy.Builder inclui todos os detectores e todos os tipos de penalidade (exceto dialog — funciona apenas quando um depurador está anexado). VmPolicy.Builder adiciona detectores para vazamentos de Activity e objetos Closable. Para projetos grandes (100+ telas), é recomendado configurar VmPolicy com penaltyDeath no detector de vazamentos de Activity — é rigoroso mas eficaz.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
}
Para controle automático em CI/CD, use penaltyDeath — se algum teste violar a política, o aplicativo falhará com uma exceção. Combine com Android Test Orchestrator para que cada teste seja executado em um processo limpo. Para testes de UI (Espresso, Compose Test), escreva um TestRule personalizado que intercepte violações do StrictMode e as transforme em falhas de assertion. Exemplo: em @Before, ative o StrictMode, e em @After, verifique se não houve violações.
Por padrão, o limite para customSlowCall é 2000 ms, para disk_read e disk_write — sem limite (qualquer operação aciona). Através de setSlowCallDurationThreshold e setSlowIoDurationThreshold, você pode definir seus próprios valores em milissegundos. Se seu aplicativo lê legitimamente SharedPreferences na thread principal (config pequena), aumente o limite para 10–20 ms — isso filtrará leituras rápidas enquanto mantém as lentas.
StrictMode é uma ferramenta poderosa mas delicada. Configuração incorreta leva a milhões de falsos positivos, fazendo com que os desenvolvedores parem de prestar atenção neles. Abaixo estão práticas comprovadas reunidas da experiência de grandes equipes Android.
Esta é uma regra rígida: StrictMode NUNCA deve estar ativo em builds de lançamento. Use o flag BuildConfig.DEBUG ou um buildConfigField personalizado. Em builds de lançamento, muitas bibliotecas de terceiros legitimamente executam operações na thread principal (inicialização de SDK, escrita de cache), e o StrictMode criará falsos positivos. Além disso, penaltyDialog em um build de lançamento mostrará um diálogo ao usuário final — o que é inaceitável.
Para projetos pequenos (1–10 telas), configure penaltyLog — logs são suficientes para análise manual. Para projetos médios (10–50 telas), adicione penaltyDeath em network e customSlowCalls. Para projetos grandes (50+ telas), ative o conjunto completo de políticas com penaltyDeath em CI/CD, e penaltyLog para desenvolvimento local. Essa gradação evita sobrecarregar os desenvolvedores com falsos crashes enquanto controla rigorosamente a qualidade no pipeline.
Algumas bibliotecas (Firebase, Crashlytics, Adjust) legitimamente executam operações em segundo plano que o StrictMode pode detectar incorretamente. Soluções: adicione a biblioteca a uma lista branca através de penaltyListener, atualize a biblioteca para uma versão com comutação explícita para thread em segundo plano, ou use StrictMode.vmPolicy. No Android 11+, foi introduzido StrictMode.OnVmViolationListener para filtragem programática de violações por stack trace.
// Filtrando falsos positivos através de penaltyListener
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyListener { violation ->
val stack = violation.stackTraceToString()
if ("com.google.firebase" !in stack) {
logViolation(violation)
}
}
.build()
)
StrictMode não é a única ferramenta de controle de qualidade no ecossistema Android. Para entender seu lugar, vamos compará-la com Android Lint, Android Profiler e Perfetto em critérios-chave: tempo de verificação, profundidade de análise e automação.
| Critério | StrictMode | Android Lint | Profiler / Perfetto |
|---|---|---|---|
| Tempo de verificação | Runtime (enquanto o app está executando) | Tempo de compilação (antes do lançamento) | Runtime (post-mortem) |
| O que verifica | Disco, rede, vazamentos | XML, código, recursos | CPU, memória, rede, energia |
| Automação | CI/CD via penaltyDeath | Tarefa Gradle + lint-baseline | Requer análise manual |
| Profundidade | Apenas thread de UI e vazamentos | Análise estática de código | Imagem completa de desempenho |
| Falsos positivos | Médios (dependem das bibliotecas) | Baixos (regras configuradas) | Nenhum (medições reais) |
A melhor estratégia é combinar todas as três abordagens: Android Lint captura erros óbvios em tempo de compilação (por exemplo, um IdleHandler esquecido), StrictMode detecta problemas em tempo de execução, e Android Profiler / Perfetto é usado para análise profunda quando as duas primeiras ferramentas não fornecem respostas. Em projetos reais (Google Maps, Instagram), o StrictMode é introduzido na segunda semana de desenvolvimento — logo após configurar a arquitetura básica.
Vamos ver dois cenários reais onde o StrictMode ajuda a detectar e corrigir problemas de desempenho: leitura de SharedPreferences na thread principal e vazamento de Activity através de um callback não registrado.
Na inicialização do aplicativo, o StrictMode com a política detectDiskReads detectará a leitura de SharedPreferences na thread principal. Solução: carregar a configuração assincronamente através de CoroutineScope ou armazenar em cache na memória na inicialização. SharedPreferences lê sincronamente um arquivo XML do disco — mesmo com um arquivo pequeno (1–2 KB), a operação leva de 1 a 5 ms, e até 20 ms em dispositivos baratos, o que pode causar queda de quadros.
// ❌ Código problemático — leitura de SharedPrefs na thread de UI
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// StrictMode detectDiskReads → VIOLAÇÃO!
prefs = getSharedPreferences("config", MODE_PRIVATE)
}
}
// ✅ Código corrigido — leitura via Coroutine
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadConfigAsync()
}
}
StrictMode com VmPolicy.detectActivityLeaks detectará uma Activity que saiu da pilha (finish foi chamado) mas o objeto Activity permanece na memória devido a uma referência estática ou um callback não registrado. Cenário típico: registrar EventBus ou LocationListener em onResume sem chamar unregister em onPause. VmPolicy exibirá um stack trace indicando a linha onde a referência foi criada.
// ❌ Vazamento — callback não cancelado
private var locationCallback: LocationCallback? = null
override fun onResume() {
super.onResume()
locationCallback = LocationCallback(this::onLocationUpdated)
locationManager.register(locationCallback) // StrictMode → VAZAMENTO!
}
override fun onPause() {
super.onPause()
// Esqueceu: locationManager.unregister(locationCallback)
}
Perguntas frequentes
StrictMode realmente adiciona uma pequena sobrecarga — cada chamada de sistema é verificada contra as políticas. O impacto no desempenho é de 1–3% em builds de depuração e está ausente em release (onde o StrictMode é desativado). Ao ativar detectAll em dispositivos antigos (Android 6–8), a sobrecarga pode chegar a 5%, por isso é recomendado configurar apenas as políticas necessárias.
Sim, StrictMode é totalmente compatível com Jetpack Compose. As políticas de disco e rede funcionam no nível do framework, independentemente do framework de UI. Além disso, no Compose a criticidade dos bloqueios de UI é maior — o Compose redesenha quadros a 120 FPS em dispositivos com alta taxa de atualização, então 5 ms extras na leitura de arquivo se tornam mais perceptíveis.
A partir do Android 8.1 (API 27), o SharedPreferences pode usar cache em memória — se o arquivo já foi lido, a releitura não acionará o StrictMode. Certifique-se de estar chamando getSharedPreferences pela primeira vez (leitura a frio) e que a política detectDiskReads está ativa. Verifique também se o StrictMode não foi sobrescrito em um fragment sem pai.
Em testes JUnit, use StrictMode.allowThreadDiskReads() e StrictMode.allowThreadDiskWrites() em @Before, e restaure as configurações em @After via StrictMode.enableDefaults(). Para testes de Instrumentação, use um TestRunner personalizado com preservação temporária da política original. Em testes Espresso, é conveniente envolver o código sensível ao StrictMode em um IdlingResource.
StrictMode funciona apenas na plataforma Android através do Android SDK. No Kotlin Multiplatform (KMP), o código commonMain não pode usar StrictMode, mas para androidMain você pode adicioná-lo normalmente. Para a parte iOS, use um análogo — a asserção DispatchQueue.main.async para a thread principal.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também