В чем разница между dispose и deactivate в жизненном цикле State?

«В чем разница между dispose и deactivate в жизненном цикле State?» — вопрос из категории Жизненный цикл, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба метода являются частью жизненного цикла объекта State в Flutter, но вызываются в принципиально разных сценариях.

deactivate()

  • Когда вызывается: Когда виджет, связанный с этим State, удаляется из дерева виджетов, но фреймворк может позже вставить его обратно в это же или другое место.
  • Типичный сценарий: Перемещение виджета с GlobalKey в другую часть дерева. Flutter оптимизирует производительность, сохраняя State.
  • Что здесь делать: Временная приостановка активности (например, пауза анимации или таймера), но не окончательное освобождение ресурсов.

dispose()

  • Когда вызывается: Когда объект State удаляется навсегда и больше никогда не будет использован. Это финальная точка жизненного цикла.
  • Типичный сценарий: Закрытие экрана (страницы), удаление виджета без GlobalKey.
  • Что здесь делать (обязательно): Освобождение всех занятых ресурсов для предотвращения утечек памяти:
    • Закрытие StreamController и отписка от StreamSubscription.
    • Вызов .dispose() у AnimationController, TextEditingController, ScrollController.
    • Закрытие открытых файловых дескрипторов или сетевых соединений.

Пример:

class _MyWidgetState extends State<MyWidget> {
  late StreamSubscription<int> _subscription;
  late AnimationController _animationController;

  @override
  void initState() {
    super.initState();
    _subscription = myStream.listen((data) { /* ... */ });
    _animationController = AnimationController(vsync: this);
  }

  @override
  void deactivate() {
    // Виджет временно скрыли. Можно приостановить анимацию.
    _animationController.stop();
    super.deactivate();
  }

  @override
  void dispose() {
    // Виджет уничтожается. Освобождаем ресурсы.
    _subscription.cancel(); // Критически важно!
    _animationController.dispose(); // Критически важно!
    super.dispose();
  }
}

Итог: deactivate — это «пауза», dispose — это «окончательное удаление». Все тяжелые ресурсы освобождаются только в dispose().