Por que Widgets const ainda são reconstruídos no Flutter — Uma otimização mal compreendida
Você abre seu aplicativo. Ele trava por 2 segundos. Você entra em pânico. O PM (Gerente de Produto) entra em pânico. O usuário? Ele já desinstalou e deixou uma avaliação de 1 estrela dizendo:
“Ideia legal, mas lento pra caramba.” 💀
Enquanto isso, em algum lugar num universo paralelo, um desenvolvedor sênior come um chocolate e faz… absolutamente nada. Porque, às vezes, fazer nada é a otimização mais inteligente que você pode fazer.
Mas aqui está o “pulo do gato”: O problema não é a lógica do seu código. É quando você está fazendo as coisas — não o que você está fazendo.
Bem-vindo ao mundo mágico da lazy initialization (inicialização tardia/preguiçosa) — onde fazer nada a princípio pode ser a coisa mais esperta que você já fez.
O Que É Lazy Initialization? Lazy initialization significa que você adia a criação de algo até que ele seja realmente necessário.
É só isso. Sem configurações desnecessárias. Sem construtores inchados. Apenas o bom e velho “Vou lidar com isso mais tarde — se eu tiver que lidar.”
Pense da seguinte forma: Se o seu aplicativo fosse uma festa em casa, a lazy initialization seria como só cozinhar o macarrão quando os convidados pedirem comida — e não no momento em que eles entram pela porta.
A Maldição do Cold Start (Inicialização a Frio) Vamos conhecer o Dev Exagerado (eu faço parte desse time).
Eles são inteligentes. Ambiciosos. Otimistas. Eles querem preparar tudo antes mesmo que o aplicativo mostre um único pixel. Porque, ei — e se o usuário magicamente precisar de todas as funcionalidades de uma só vez?
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
final crashlytics = Crashlytics(); // O App nem travou ainda
final db = await HeavyLocalDatabase.init(); // O usuário nem sequer fez login
final analytics = AnalyticsService(); // Nenhum comportamento para analisar ainda
final prefs = await SharedPreferences.getInstance(); // Configurações que ninguém pediu ainda
final monthlyReport = MonthlyReportGenerator(); // Para um relatório previsto para o próximo trimestre
final ads = await AdSdk.init(); // A gente nem sabe se anúncios serão exibidos ainda
runApp(MyApp());
}
O Problema?
- Você está inicializando tudo.
- Tudo de uma vez.
- Antes mesmo que o app consiga respirar.
Isso é como levar bagagem para uma viagem de um ano — para uma caminhada de 10 minutos.
A Solução: Lazy Initialization com get_it.
Vamos apresentar o get_it, o mordomo de serviços do seu app.
- crie um arquivo
locator.dart:
import 'package:get_it/get_it.dart';
final locator = GetIt.instance;
void setupLocator() {
// Register lazily — created only when first accessed
locator.registerLazySingleton<Crashlytics>(() => Crashlytics());
locator.registerLazySingletonAsync<HeavyLocalDatabase>(
() async => await HeavyLocalDatabase.init(),
);
locator.registerLazySingleton<AnalyticsService>(() => AnalyticsService());
locator.registerLazySingletonAsync<SharedPreferences>(
() async => await SharedPreferences.getInstance(),
);
locator.registerLazySingletonAsync<AdSdk>(
() async => await AdSdk.init(),
);
locator.registerFactory<MonthlyReportGenerator>(
() => MonthlyReportGenerator(),
);
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
setupLocator();
runApp(MyApp());
}
O Salvador do StatefulWidget: Lazy Getter.
A maioria de nós trata o initState() como uma lista de compras de supermercado — ‘Vamos pegar tudo o que a gente talvez precise mais tarde… só por garantia.‘
Mas esse ‘só por garantia’ geralmente leva a:
- Primeiros frames mais lentos.
- Serviços não utilizados consumindo memória desnecessariamente.
- Código mais difícil de gerenciar e testar.
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
@override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController( // ❌ Always created
vsync: this,
duration: const Duration(seconds: 1),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
_controller.forward(from: 0);
},
child: const Text("Animate"),
),
),
);
}
}
Problema:
- O
_controlleré inicializado noinitState()de qualquer maneira. - Mesmo que o usuário nunca toque no botão, o
_controllerainda é criado e fica na memória fazendo… nada. - Se for um objeto pesado (como DB, analytics, etc.), você desperdiça recursos.
- Vamos consertar isso — do jeito preguiçoso (lazy way).
Com um Lazy Getter
class _DashboardScreenState extends State<DashboardScreen>
with SingleTickerProviderStateMixin {
AnimationController get _controller => _lazyController ??=
AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
AnimationController? _lazyController;
@override
void dispose() {
_lazyController?.dispose(); // ✅ Only dispose if created
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
_controller.forward(from: 0); // ✅ Created only when used
},
child: const Text("Animate"),
),
),
);
}
}
Benefício:
- O controlador de animação só é criado quando você realmente precisa dele.
- Se a animação nunca rodar, seu app nunca gasta recursos com ela.
- O mesmo comportamento para o usuário, um comportamento melhor para o dispositivo.
A lazy initialization permite que você seja estrategicamente preguiçoso — como um verdadeiro dev sênior.
Então relaxe, adie aquela configuração pesada e deixe seu app respirar.
Porque, às vezes, a melhor otimização… …é não fazer absolutamente nada.
Deixe sua opinião nos comentários. E se isso te fez rir ou deixou seu app mais rápido, vá em frente, compartilhe com aquele colega dev Flutter que ainda está complicando as coisas (doing the most).
Não tenha medo de quebrar coisas. Falhe rápido. Corrija mais rápido ainda. Até a próxima ❤️.