Flutter num Android de 700 reais: o que eu mudei pro app parar de engasgar
mais de 60% dos nossos usuários usam celular de entrada. a gente testava em iPhone. pois é
Contents
mano, vou contar uma vergonha. nosso app (fintech: extrato, pix, cartão) tinha nota 4.6 na App Store e 3.9 na Play Store. e a gente achava que era "usuário de Android que reclama mais" kkkkk. aí alguém finalmente abriu o analytics: mais de 60% dos usuários Android tinham celular com 2 ou 3 GB de RAM. e o time inteiro testava em iPhone e Pixel.
compramos 3 aparelhos de entrada (o mais barato saiu uns 700 reais) e fomos sofrer. o que a gente mudou:
0. medir em profile mode, no aparelho ruim
flutter run --profile
e abre o DevTools na aba Performance. nunca mede em debug, debug é lento de propósito. a gente perdeu uma semana otimizando coisa que só era lenta em debug.
1. a tela de extrato construía 2.000 widgets de uma vez
tava assim: ListView(children: transacoes.map(...).toList()). ou seja, constrói tudo, até o que não aparece na tela. trocamos por:
ListView.builder(
itemCount: transacoes.length,
itemExtent: 72,
itemBuilder: (context, i) => TransacaoTile(transacao: transacoes[i]),
)
o itemExtent fixo ajuda muito: o Flutter não precisa medir cada item pra saber onde o scroll tá. se tua altura não é fixa, olha o prototypeItem.
2. imagem decodificada no tamanho original
os logos das lojas no extrato vinham da API em 512x512 e a gente mostrava em 40x40. o Flutter decodificava 512x512 na memória, pra cada logo. em celular de 2GB isso é pedir pra morrer.
Image.network(
logoUrl,
width: 40,
height: 40,
cacheWidth: (40 * MediaQuery.devicePixelRatioOf(context)).round(),
)
com cacheWidth ele já decodifica no tamanho certo. a memória dessa tela caiu absurdamente.
3. Opacity em animação
a gente animava o saldo (mostrar/esconder) com Opacity dentro de um AnimatedBuilder. isso força uma camada extra a cada frame. troca por FadeTransition ou AnimatedOpacity, que é o que a própria doc do Flutter recomenda.
4. o blur do header
o designer amava um BackdropFilter com blur atrás do saldo. lindo no iPhone. no aparelho de 700 reais era um slideshow. hoje a gente desliga o blur em aparelho fraco e usa uma cor sólida com transparência. ninguém reclamou, ninguém percebeu.
5. const e widgets pequenos
parece bobo mas: const em tudo que dá, e quebrar aquele build() de 400 linhas em widgets menores. assim um setState no contador de notificação não reconstrói a tela inteira.
6. inicialização depois do primeiro frame
a gente inicializava remote config, analytics e mais 3 SDKs antes do runApp. o app ficava 4 segundos na splash no celular barato. jogamos o que não é essencial pra depois do primeiro frame:
WidgetsBinding.instance.addPostFrameCallback((_) {
inicializarCoisasQueNaoSaoUrgentes();
});
resultado
no aparelho de entrada, frames travados na tela de extrato caíram de uns 30% pra menos de 5%. cold start de uns 4s pra 1,8s. a nota na Play Store subiu pra 4.3 em dois meses. nada disso é mágica, é só testar no celular que teu usuário usa.
caio, antes que você fale: sim, em Kotlin nativo ia ter que fazer metade disso também kkkkk
Written by
Thiago Valadares
Flutter dev numa fintech em SP. PJ com orgulho (e sem férias kkkk). Corinthiano sofredor. Posto sobre mobile, carreira e vaga gringa.
Get the best of #thumb_zone weekly
One email each Monday with the most useful posts. No spam; unsubscribe in one click.
Comments
Sign in to join the conversation.
Sign in to comment