Aula 17 - Gerenciamento de Estado Avançado com BLoC e Provider 🎯
Objetivo Pedagógico
Objetivo: Dominar a arquitetura reativa em Flutter utilizando o padrão BLoC (Business Logic Component) com Streams de Dart, separando integralmente a lógica de negócios da camada de apresentação de widgets.
📑 1. Fundamentos Teóricos & Análise Técnica
O Flutter renderiza sua própria árvore de renderização gráfica diretamente sobre sua engine C++ (Impeller/Skia). No entanto, o uso ingênuo de chamadas a setState() em árvores de widgets profundas reconstrói a subárvore inteira, gerando queda de taxa de quadros e desorganização da lógica de controle.
O padrão BLoC (Business Logic Component) foi concebido pelo Google para resolver esse desafio: 1. O Mecanismo Baseado em Streams: - A comunicação entre os widgets e a lógica de negócios ocorre exclusivamente por meio de fluxos contínuos de dados (Streams e StreamControllers do Dart). - Events (Entradas): Ações emitidas pela interface (ex: AdicionarItemAoCarrinho, CarregarPerfil). - States (Saídas): Estados imutáveis emitidos pelo BLoC que informam à interface o que renderizar. 2. Equitable e Otimização de Reconstrução: - A biblioteca equatable implementa comparação por valor em vez de referência de memória. - O widget BlocBuilder utiliza a propriedade buildWhen(previous, current) para avaliar se o estado mudou de fato, evitando reconstruções idênticas na tela. 3. Injeção de BLoCs na Árvore de Widgets: - Utilização do BlocProvider para disponibilizar instâncias de BLoCs em escopos específicos da árvore de widgets via InheritedWidget, garantindo o fechamento automático (Dispose) das Streams quando a rota de navegação é desmontada.
📐 Arquitetura Conceitual & Diagrama de Fluxo
graph LR
Widget["UI: Flutter Widgets"] -->|Despacha Evento (add)| Bloc["BLoC Component (StreamTransformer)"]
Bloc -->|Executa Regra / Chama Repo| Repo["Data Repository"]
Repo -->|Retorna Dados| Bloc
Bloc -->|Emite Novo State (emit)| Stream["Stream de Estados Imutáveis"]
Stream -->|BlocBuilder / BlocConsumer| Widget
style Widget fill:#e1f5fe,stroke:#01579b
style Bloc fill:#fff3e0,stroke:#e65100
style Repo fill:#f3e5f5,stroke:#7b1fa2
style Stream fill:#e8f5e9,stroke:#2e7d32 🔍 Pilares e Diretrizes Técnicas
Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Separação Estrita de Responsabilidades: Nenhum widget de interface deve conter código de acesso a dados ou regras matemáticas de negócio. - Imutabilidade de Estados com Equatable: Previne rebuilds desnecessários comparando o conteúdo das propriedades dos estados emitidos. - Tratamento de Concorrência com Transformers: Uso de operadores como restartable() ou droppable() para evitar requisições redundantes de busca enquanto o usuário digita. - Gerenciamento do Ciclo de Vida do Stream: Fechamento obrigatório dos controladores de fluxo para prevenir vazamentos de memória na VM do Dart.
🛠️ 2. Implementação Prática em Flutter Multiplataforma, Dart Streams e BLoC Pattern
Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:
// cart_bloc.dart (BLoC Reativo com Eventos, Estados e BlocBuilder)
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
// 1. Definição de Eventos
abstract class CartEvent extends Equatable {
const CartEvent();
@override
List<Object?> get props => [];
}
class AddProductEvent extends CartEvent {
final String productId;
const AddProductEvent(this.productId);
@override
List<Object?> get props => [productId];
}
// 2. Definição de Estados Imutáveis
abstract class CartState extends Equatable {
const CartState();
@override
List<Object?> get props => [];
}
class CartInitial extends CartState {}
class CartLoadedState extends CartState {
final List<String> items;
final double totalPrice;
const CartLoadedState({required this.items, required this.totalPrice});
@override
List<Object?> get props => [items, totalPrice];
}
// 3. Implementação do BLoC
class CartBloc extends Bloc<CartEvent, CartState> {
CartBloc() : super(CartInitial()) {
on<AddProductEvent>((event, emit) async {
final currentItems = state is CartLoadedState
? List<String>.from((state as CartLoadedState).items)
: <String>[];
currentItems.add(event.productId);
final newPrice = currentItems.length * 49.90;
emit(CartLoadedState(items: currentItems, totalPrice: newPrice));
});
}
}
💡 Análise Passo a Passo do Código
- Uso de
Equatable: Permite ao Flutter BLoC deduzir se os itens do carrinho realmente mudaram antes de acionar o redesenho dos widgets. - Manipulação Segura com
emit: Garante despacho sequencial de novos estados através do pipeline interno de corrotinas do Dart. - Tipagem Rígida em Eventos: Fornece segurança contra parâmetros nulos ou eventos desconhecidos em tempo de compilação.
🎯 3. Próximos Passos & Sequência Didática
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto