Introdução
Recentemente, fiquei surpreso ao descobrir que meus colegas não têm clareza completa do que é assincronia em Flutter. Por algum motivo, eles tiveram a ideia de que se a função assíncrona for escrita corretamente, ela não bloqueará a interface. Depois de ler alguns artigos, não encontrei uma explicação simples, completa e clara de toda esta cozinha (tudo está de acordo com o princípio - "escolha 2 entre 3")). Em um artigo, até li que o Dart tem uma assincronia maravilhosa, que permite adiar a execução do código até que o thread esteja mais livre (o que na minha opinião é um pouco enganador) (Nota: nos comentários nikita_dolapontou o que provavelmente significava - scheduleTask ).
Para quem o artigo
O artigo é direcionado para aqueles que estão começando a se familiarizar com o Flutter, então tentarei mostrar com um exemplo simples nesta pequena nota que assincronia é apenas a capacidade de executar código não sequencialmente. Mas, se você tiver uma função "pesada" (mesmo que seja três vezes assíncrona), ela ainda bloqueará a interface para você. Claro, em um produto real, é improvável que você encontre tais manifestações óbvias (no momento, os processadores são bastante poderosos), mas ainda vale a pena entender como isso funciona.
Vai
E então, vamos pegar um exemplo da documentação da biblioteca flutter_bloc para experimentos . Vamos modificar ligeiramente a função "_mapTimerStartedToState" da classe timer_bloc - comentar a atualização do contador para que não interfira:
Stream<TimerState> _mapTimerStartedToState(TimerStarted start) async* {
yield TimerRunInProgress(start.duration);
_tickerSubscription?.cancel();
// _tickerSubscription = _ticker
// .tick(ticks: start.duration)
// .listen((duration) => add(TimerTicked(duration: duration)));
}
Vamos adicionar uma nova função estática (nós a deixamos assim com antecedência - isolar funciona apenas com eles) função:
static Future<void> _heavyComput (SendPort sendPort) async {
await Future.delayed(Duration(seconds: 5));
print('=======================');
print('!!!function finished!!!');
print('=======================');
return null;
}
Aqui, como uma emulação de cálculos pesados, aguardamos o fim do atraso de 5 segundos.
Modificamos a função mapEventToState - adicionamos uma chamada assíncrona a _heavyComput no final:
@override
Stream<TimerState> mapEventToState(
TimerEvent event,
) async* {
. . .
_heavyComput(null);
}
Para o primeiro teste, tudo está pronto - nossa tarefa é observar as ondas mágicas.
Lançamos e vemos - as ondas estão preocupadas, a interface não está bloqueada, a mensagem sobre o fim da função é exibida após 5 segundos.
Isso é assincronia maravilhosa - o pânico era falso. Hmm ... E se Future.delayed (Duration (seconds: 5)) for substituído por um loop?
static Future<void> _heavyComput(SendPort sendPort) async {
int pause = 1200000000;
for (int i = 0; i < pause; i++) {}
print('=======================');
print('!!!function finished!!!');
print('=======================');
return null;
}
Lançamos e pronto - “chegamos” - as ondas não preocupam mais.
Não acho que muita explicação seja necessária aqui: até mesmo uma função pesada assíncrona bloqueia tudo. Por padrão, todo o código é executado em um segmento. Só que, no primeiro caso, nenhum cálculo foi necessário, mas você apenas teve que esperar e, no segundo, os cálculos foram necessários.
Bem, e para que o artigo não se torne completamente microscópico, vamos chamar essa função usando isolar. Vamos mudar o mapEventToState:
@override
Stream<TimerState> mapEventToState(
TimerEvent event,
) async* {
. . .
var _receivePort = ReceivePort();
var _isolate = Isolate.spawn(_heavyComput, _receivePort.sendPort);
}
Iniciamos e vemos que a interface não está bloqueada, recebemos uma mensagem sobre a conclusão da função com um atraso notável.
Isso é tudo (que trabalho assíncrono e aguardar - há muitos artigos, acho que você não deveria parar por aí).
Um exemplo pode ser baixado do link - flutter_timer_async_and_parallels