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.