Pare de criar God ViewModels: um ViewModel por composable, não por tela
Duas novas APIs do Android Lifecycle (rememberViewModelStoreOwner e rememberViewModelStoreProvider) permitem escopar ViewModels ao ciclo de vida de um composable específico — eliminando ViewModels inchados que vivem mais do que a UI que servem.
Comentário do autor
Esse padrão de 'um ViewModel por tela' virou dogma e a gente paga caro: estado de diálogo, aba e página de pager grudado num ViewModel gigante que nunca morre na hora certa. Essas duas APIs novas resolvem isso de um jeito que finalmente combina com a filosofia do Compose. Recomendo muito a leitura para ficar por dentro do que vem por aí!
Visão Geral
O padrão "uma tela = um ViewModel" virou regra silenciosa no Android, mas ele
amarra o ciclo de vida do ViewModel à Activity, Fragment ou destino de navegação.
O resultado são os God ViewModels: classes enormes que seguram estado de diálogos,
abas e páginas de pager, vivem mais do que a UI que servem e desperdiçam memória.
O problema do escopo tradicional
- ViewModels persistem por mais tempo do que o necessário
- Estado temporário de UI ocupa memória à toa
- Páginas de um pager compartilham estado sem querer
- O momento de limpeza (
onCleared) fica ambíguo em UIs dinâmicas
O que há de novo
Duas APIs do Lifecycle permitem dar a um composable seu próprio ViewModelStoreOwner:
rememberViewModelStoreOwner()— escopa um ViewModel ao tempo de vida de um composable específicorememberViewModelStoreProvider()— cria owners independentes para itens de pagers, abas e listas
Exemplo prático
Escopando um ViewModel a um trecho da composição:
Kotlin1@Composable 2fun DetailDialog() { 3 val storeOwner = rememberViewModelStoreOwner() 4 CompositionLocalProvider(LocalViewModelStoreOwner provides storeOwner) { 5 val viewModel: DialogViewModel = viewModel() 6 // O ViewModel é limpo quando este composable sai da composição 7 } 8}
ViewModels independentes por página de um pager:
Kotlin1val provider = rememberViewModelStoreProvider() 2 3HorizontalPager(state = pagerState) { page -> 4 val owner = provider.getViewModelStoreOwner(key = page) 5 CompositionLocalProvider(LocalViewModelStoreOwner provides owner) { 6 val pageVm: PageViewModel = viewModel() 7 } 8}
Quando usar
Bons candidatos: diálogos, bottom sheets, páginas de pager, painéis expansíveis e fluxos de feature aninhados. Evite escopar componentes triviais e sem estado — o custo não compensa.
A ideia central
Mudanças de configuração continuam funcionando normalmente. O princípio é: a UI define o ciclo de vida, e não o contrário — alinhando a posse do ViewModel à estrutura real da composição.
Esse conteúdo faz parte do CAMP Platform
Cursos práticos de Android Moderno com Kotlin e Jetpack Compose, arquitetura limpa, assistente IA e uma comunidade de devs profissionais.