You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决FocusNode实现后返回箭头导航引发的异常?

问题分析与解决方案

问题根源

点击TextField后返回主页面时,_onFocusChange方法里的Future.delayed会在页面的State已被销毁后,仍尝试执行setState操作。这会触发Flutter框架的未捕获异常——因为不允许在已销毁的State实例上调用setState,最终导致主页面UI冻结、无法响应交互。

返回操作会立刻销毁MyHomePage的State,但延迟500ms的回调还在事件队列中,当回调执行时,State已经不存在,此时的setState调用会破坏UI状态一致性。

修复方案

方案1:执行setState前检查挂载状态

修改_onFocusChange方法,在更新状态前先判断当前State是否仍处于挂载状态:

void _onFocusChange() {
  Future.delayed(const Duration(milliseconds: 500), () {
    // 仅在State未销毁时执行状态更新
    if (mounted) {
      setState(() {
        heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
        setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
      });
    }
  });
}

方案2:用可取消任务管理延迟操作

借助async包的CancelableOperation,在页面销毁时主动取消未执行的延迟任务:

  1. 先在pubspec.yaml添加依赖:
dependencies:
  flutter:
    sdk: flutter
  async: ^2.11.0 # 可使用最新版本
  1. 修改MyHomePage的State代码:
import 'package:async/async.dart';

class _MyHomePageState extends State<MyHomePage> {
  // ... 其他变量
  CancelableOperation? _focusDelayTask;

  void _onFocusChange() {
    // 取消之前未完成的任务,避免重复执行
    _focusDelayTask?.cancel();
    _focusDelayTask = CancelableOperation.fromFuture(
      Future.delayed(const Duration(milliseconds: 500), () {
        setState(() {
          heightKeyboard = MediaQuery.of(context).viewInsets.bottom;
          setDropdownMenuHeight(heightAppBar, heightTextField, heightKeyboard);
        });
      }),
    );
  }

  @override
  void dispose() {
    _focusDelayTask?.cancel(); // 销毁前取消延迟任务
    _focusNode.unfocus(); // 主动取消焦点,清理键盘相关状态
    _focusNode.removeListener(_onFocusChange);
    _focusNode.dispose();
    firstController.dispose();
    super.dispose();
  }

  // ... 其他代码
}

验证步骤

修改代码后按以下流程测试:

  • 点击主页面TextButton进入MyHomePage
  • 点击TextField唤起键盘
  • 点击返回箭头回到主页面
  • 再次点击TextButton,确认可正常跳转,UI无冻结

内容的提问来源于stack exchange,提问作者rusty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:14:52