As Streams e Blocs são conceitos avançados de Dart que permitem a manipulação de dados de maneira assíncrona e reativa, respectivamente. Esses conceitos são fundamentais para a criação de aplicativos complexos e eficientes, e são amplamente utilizados no Flutter.
Streams
Em Dart, uma Stream é uma sequência de eventos assíncronos. Ela pode emitir zero ou mais eventos de dados, e um evento de erro ou de conclusão. Os eventos de dados são emitidos sequencialmente e podem ser consumidos por um ouvinte, que é uma função que processa os eventos à medida que ocorrem.
Uma Stream pode ser criada de várias maneiras. A maneira mais simples é usar a função Stream.fromIterable, que cria uma Stream a partir de uma coleção iterável. Por exemplo:
var numbers = [1, 2, 3, 4, 5];
var stream = Stream.fromIterable(numbers);
stream.listen((number) {
print(number);
});
Este código cria uma Stream que emite os números de 1 a 5, um de cada vez. A função listen é usada para registrar um ouvinte que imprime cada número à medida que é emitido.
As Streams também podem ser criadas a partir de fontes assíncronas de dados, como arquivos ou conexões de rede. Por exemplo, a classe File em Dart tem um método openRead que retorna uma Stream de bytes. Este método pode ser usado para ler um arquivo de maneira assíncrona, como neste exemplo:
var file = File('file.txt');
var stream = file.openRead();
stream.listen((data) {
print(String.fromCharCodes(data));
});
Este código lê um arquivo chamado 'file.txt' e imprime seu conteúdo como texto. A Stream emite eventos de dados à medida que os bytes são lidos do arquivo, e o ouvinte os converte em texto e os imprime.
Blocs
Em Flutter, o padrão Bloc (Business Logic Component) é usado para separar a lógica de negócios da interface do usuário. Um Bloc é uma classe que expõe uma Stream de estados e aceita eventos. A lógica de negócios é implementada como uma função que mapeia eventos para estados.
Por exemplo, considere um aplicativo de lista de tarefas. A interface do usuário pode emitir eventos como 'adicionar tarefa' ou 'remover tarefa', e o estado do aplicativo pode ser a lista atual de tarefas. Um Bloc para este aplicativo pode ser implementado da seguinte maneira:
class TodoBloc {
final _stateController = StreamController>();
final _eventController = StreamController();
Stream> get stateStream => _stateController.stream;
Sink get eventSink => _eventController.sink;
TodoBloc() {
_eventController.stream.listen(_mapEventToState);
}
void _mapEventToState(Event event) {
// implement business logic here
}
void dispose() {
_stateController.close();
_eventController.close();
}
}
Este código define um Bloc que tem uma Stream de estados e um Sink de eventos. O Sink é uma interface que permite adicionar eventos à Stream. O método _mapEventToState é chamado para cada evento, e é responsável por atualizar o estado com base no evento.
Em resumo, as Streams e Blocs são conceitos poderosos de Dart que permitem criar aplicativos reativos e eficientes. As Streams permitem manipular dados de maneira assíncrona, enquanto os Blocs permitem separar a lógica de negócios da interface do usuário. Ambos são fundamentais para a criação de aplicativos complexos com Flutter.