Программируя на Flutter невозможно избежать использования асинхронных методов, таких как чтение данных из сети интернет, файлов и баз данных. Работа таких методов выводится в отдельные потоки и не нарушает работы основного потока программы: вычисление и отображение интерфейса. Одним словом, функции которые выполняются относительно долго — должны быть асинхронными.
В этом уроке мы научимся составлять и использовать такие методы. А уже в следующем начнем получать и обрабатывать данные из сети интернет.
Создание асинхронного метода на образе песочных часов
Создадим класс песочные часы, в которых есть 100 песчинок, и когда они в верхней части, значение sand=100, когда все песчинки в нижней части — тогда sand=0
class SandGlass {
int _sand = 0;
}
Добавим метод, который возвращает текущие состояние, он будет синхронным, т.е. по вызову он будет возвращать текущее значение приватной переменной _sand.
time(){
return _sand;
}
Добавим асинхронный метод tick, он будет «перемещать песчинки» из «верхней части» в нижнюю со скоростью 1/100 [песчинки/миллисекунды]. Чтобы метод был асинхронным, нужно указать модификатор async между сигнатурой функции и ее телом.
tick() async {
}
Еще можно написать эту функцию так:
Future tick() async {
}
Оба варианта дают одинаковый результат: вызывая асинхронную функцию мы всегда получаем в ответ Future — обещание.
Для проверки можно вывести в консоль любую асинхронную функцию и в выводе будет обещание Future: print(‘${tick()}’);
Для работы с асинхронными функциями как с синхронными служит await — ожидание.
await позволяет дождаться выполнения асинхронной функции и после обработать результат, если он есть.
Так например функция чтения из файла — асинхронная функция, которая возвращает ожидание, но нам нужен результат чтения — содержимое файла. Для этого перед функций чтения мы должны указать await.
await можно использовать только внутри асинхронных функциях, например в функции построения виджета так сделать нельзя:
Widget build(BuildContext context) {
await clock.tick();// ошибка
Также мы не можем сделать build метод асинхронным, потому что возвращаемый тип должен быть Widget, и не может быть Future или Future<Widget>.
Но запустить асинхронный метод в build нам ничего не мешает:
Widget build(BuildContext context) {
clock.tick();// запуск асинхронного метода
Когда мы пишем tick() async или Future tick() async — то результат тела функции всегда динамический.
Но если результат функции должен быть типа bool, например условный оператор принимает только true или false:
if(await tick()) {
///…
} else {
///…
}
, нужно указать возвращаемый тип в скобках обещания:
Future<bool> tick() async
Полный листинг программы и детальное рассмотрение ее работы
import ‘package:flutter/material.dart’;
class SandGlass {
int _sand = 0;
time(){
return _sand;
}//time
Future tick() async {
_sand = 100;
print(‘Start:tick’);
while(_sand > 0) {
print(‘tick: _sand’);
_sand–;
await new Future.delayed(const Duration(milliseconds: 100));
}//while
print(‘End:tick’);
}//tick
}//SandGlass
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyAppState();
}
class MyAppState extends State {
SandGlass clock = SandGlass();
_reDrawWidget() async {
if(clock.time() == 0) return;
await new Future.delayed(const Duration(seconds: 1));
setState(() {print(‘reDrawWidget()’);});
}
@override
void initState() {
clock.tick();
super.initState();
}
@override
Widget build(BuildContext context) {
_reDrawWidget();
print(‘clock.tick: ${clock.time()}’);
return Center(child: Text(‘time is: ${clock.time()}’));
}
}
void main() => runApp(new MaterialApp(home:Scaffold(body: MyApp())));
- Самая главная функция main, вызывает функцию runApp. Выполняется вызов очереди вложенных виджетов MaterialApp:home / Scaffold:body / MyApp > MyAppState
- Рассмотрим работу MyAppState:
- В виджете есть параметр clock — экземпляр класса SandGlass.
- Асинхронный метод _reDrawWidget — вызывает перестроение виджета MyApp после задержки в 1 секунду.
- Задержка происходит с помощью ожидания асинхронной функции await new Future.delayed(const Duration(seconds: 1));
не используйте синхронную функцию sleep для этих целей. - Метод initState переопределен, он вызывается один раз при построении виджета и инициализирует запуск песочных часов: clock.tick().
- Метод build запускает выполнение асинхронной функции _reDrawWidget и выполняет вывод состояния песочных часов clock.time() в консоль и в текстовый виджет.
- Асинхронный метод tick в SandGlass:
- задает значение _sand = 100;
- выполняет цикл while(_sand > 0)
- на каждой итерации цикла происходит уменьшение значения _sand на единицу и задержка в 100 миллисекунд:
_sand–;
await new Future.delayed(const Duration(milliseconds: 100));
На скриншоте вывода консоли, можно увидеть результаты параллельной работы асинхронных методов и основного потока.

Асинхронные методы занимают важное место в Dart и Flutter, в следующем уроке мы рассмотрим http запросы.
