← Назад к вопросам

Какие знаешь механизмы для запуска задач в фоне?

2.0 Middle🔥 171 комментариев
#Асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизмы запуска фоновых задач в Flutter

Flutter предоставляет несколько механизмов для выполнения задач в фоне, от простых до сложных. Выбор механизма зависит от типа задачи, её продолжительности и требований к надежности.

1. Isolate

Isolate — это основной механизм для выполнения кода в отдельном потоке без блокировки UI:

import "dart:isolate";

void heavyTask(SendPort sendPort) {
  int result = 0;
  for (int i = 0; i < 1000000; i++) {
    result += i;
  }
  sendPort.send(result);
}

Future<void> runInIsolate() async {
  final receivePort = ReceivePort();
  await Isolate.spawn(heavyTask, receivePort.sendPort);
  
  final result = await receivePort.first;
  print("Результат: $result");
}

Преимущества:

  • Полностью изолированный поток (нет конфликтов по памяти)
  • Идеален для тяжелых вычислений
  • Не блокирует UI

Недостатки:

  • Нельзя напрямую делиться объектами
  • Требует передачи данных через SendPort/ReceivePort
  • Нельзя обновлять UI прямо из isolate

2. async/await с Future

Для менее требовательных задач используется стандартный Future:

Future<void> networkRequest() async {
  try {
    final response = await http.get(Uri.parse("https://api.example.com"));
    print("Ответ: ${response.body}");
  } catch (e) {
    print("Ошибка: $e");
  }
}

// Вызов без ожидания
networkRequest();

Когда использовать:

  • Сетевые запросы
  • Чтение файлов
  • Операции с БД

3. compute() функция

compute() — удобная обертка над Isolate для простых функций:

int fibonacci(int n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

Future<void> calculateFib() async {
  final result = await compute(fibonacci, 30);
  print("Результат: $result");
}

Преимущества:

  • Проще чем Isolate
  • Автоматическое управление портами
  • Идеален для одноразовых вычислений

4. Фоновые сервисы (Platform Channels)

Для задач, которые должны продолжаться после закрытия приложения, используются native background services:

Android (WorkManager)

import "package:workmanager/workmanager.dart";

void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {
    print("Выполняю фоновую задачу");
    return Future.value(true);
  });
}

void scheduleBackgroundTask() {
  Workmanager().registerPeriodicTask(
    "uniqueName",
    "taskName",
    frequency: Duration(minutes: 15),
  );
}

iOS (Background Modes)

Для iOS требуется конфигурация в ios/Runner/Info.plist:

<key>UIBackgroundModes</key>
<array>
  <string>fetch</string>
  <string>processing</string>
</array>

5. Timer и periodic задачи

Для регулярных задач используется Timer:

final timer = Timer.periodic(Duration(seconds: 5), (timer) {
  print("Выполняю периодическую задачу");
  // Отмена
  if (someCondition) {
    timer.cancel();
  }
});

6. Streams

Stream позволяет обрабатывать непрерывный поток данных:

Stream<int> countStream() async* {
  for (int i = 0; i < 10; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

// Использование
countStream().listen((value) {
  print("Значение: $value");
});

7. GetX для управления async задачами

Популярный пакет GetX предоставляет удобный способ:

class MyController extends GetxController {
  RxBool isLoading = false.obs;

  void fetchData() async {
    isLoading.value = true;
    try {
      // async операция
      await Future.delayed(Duration(seconds: 2));
    } finally {
      isLoading.value = false;
    }
  }
}

Сравнительная таблица

МеханизмИспользованиеСложность
Future/asyncОдна операцияНизкая
IsolateТяжелые вычисленияСредняя
compute()Простые функцииНизкая
TimerПериодические задачиНизкая
StreamПотоки данныхСредняя
WorkManagerФоновые сервисыВысокая

Практический пример: загрузка больших файлов

Future<void> downloadLargeFile() async {
  final url = "https://example.com/large-file.zip";
  final dio = Dio();
  
  try {
    await dio.download(
      url,
      "${(await getTemporaryDirectory()).path}/file.zip",
      onReceiveProgress: (received, total) {
        final progress = (received / total * 100).toStringAsFixed(0);
        print("Загружено: $progress%");
      },
    );
  } catch (e) {
    print("Ошибка: $e");
  }
}

Итоги

Выбор механизма зависит от требований:

  • Простые async операции → Future/async-await
  • Тяжелые вычисления → Isolate или compute()
  • Периодические задачи → Timer
  • Потоки данных → Stream
  • Фоновые сервисы → WorkManager/Background Modes
  • UI-bound операции → обычные Future с setState()