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

Flutter中showDialog调用Navigator.pop后不关闭,如何在弹窗关闭后执行耗时任务?

问题描述

在Flutter场景中,调用Navigator.pop()关闭弹窗后,弹窗仍会停留至_startLongRunningLoop执行完毕才消失。期望实现弹窗关闭后再执行该耗时方法,该如何解决?

简化示例代码

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Dialog Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  void _showFormDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Form Dialog'),
          content: FormDialog(),
        );
      },
    );
    _startLongRunningLoop();
  }

  void _startLongRunningLoop() {
    int count = 0;
    while (count < 1000000) {
      print('Long running loop: $count');
      count++;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Dialog Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            _showFormDialog(context);
          },
          child: Text('Open Form Dialog'),
        ),
      ),
    );
  }
}

class FormDialog extends StatefulWidget {
  @override
  _FormDialogState createState() => _FormDialogState();
}

class _FormDialogState extends State<FormDialog> {
  final _formKey = GlobalKey<FormState>();

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      Navigator.of(context).pop();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextFormField(
            decoration: InputDecoration(labelText: 'Name'),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter your name';
              }
              return null;
            },
          ),
          SizedBox(height: 16.0),
          ElevatedButton(
            onPressed: _submitForm,
            child: Text('Submit'),
          ),
        ],
      ),
    );
  }
}

已尝试方案

尝试通过await showDialog()等待弹窗关闭后再执行耗时方法,但问题依旧:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Dialog Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  void _showFormDialog(BuildContext context) async {
    var t = await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Form Dialog'),
          content: FormDialog(),
        );
      },
    );
    if (t == "true") {
      _startLongRunningLoop();
    }
  }

  void _startLongRunningLoop() {
    int count = 0;
    while (count < 1000000) {
      print('Long running loop: $count');
      count++;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Dialog Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            _showFormDialog(context);
          },
          child: Text('Open Form Dialog'),
        ),
      ),
    );
  }
}

class FormDialog extends StatefulWidget {
  @override
  _FormDialogState createState() => _FormDialogState();
}

class _FormDialogState extends State<FormDialog> {
  final _formKey = GlobalKey<FormState>();

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      Navigator.of(context).pop("true");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextFormField(
            decoration: InputDecoration(labelText: 'Name'),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter your name';
              }
              return null;
            },
          ),
          SizedBox(height: 16.0),
          ElevatedButton(
            onPressed: _submitForm,
            child: Text('Submit'),
          ),
        ],
      ),
    );
  }
}

解决方案

问题根源

Flutter的UI更新、用户交互都在主线程执行,_startLongRunningLoop是同步耗时循环,会直接阻塞主线程。即便调用了Navigator.pop(),主线程被耗时操作占用,无法及时处理UI刷新,导致弹窗迟迟不消失。

正确实现方式

将耗时操作移至独立Isolate(后台线程)执行,避免阻塞主线程。可以使用Flutter 3.10+支持的Isolate.run(),或兼容低版本的compute函数:

方式1:使用Isolate.run()(推荐Flutter 3.10+)

Future<void> _startLongRunningLoop() async {
  // 将耗时操作放入独立Isolate执行
  await Isolate.run(() {
    int count = 0;
    while (count < 1000000) {
      print('Long running loop: $count');
      count++;
    }
  });
}

方式2:使用compute函数(兼容低版本)

Future<void> _startLongRunningLoop() async {
  await compute(_longRunningTask, null);
}

// 耗时任务必须是顶级函数或static函数
void _longRunningTask(_) {
  int count = 0;
  while (count < 1000000) {
    print('Long running loop: $count');
    count++;
  }
}

完整修改后的代码

结合你已尝试的await showDialog()逻辑,最终代码如下:

import 'package:flutter/material.dart';
import 'dart:isolate';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Dialog Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  void _showFormDialog(BuildContext context) async {
    var result = await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('表单弹窗'),
          content: FormDialog(),
        );
      },
    );
    if (result == "true") {
      await _startLongRunningLoop();
    }
  }

  Future<void> _startLongRunningLoop() async {
    await Isolate.run(() {
      int count = 0;
      while (count < 1000000) {
        print('耗时循环执行中: $count');
        count++;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter弹窗示例'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            _showFormDialog(context);
          },
          child: Text('打开表单弹窗'),
        ),
      ),
    );
  }
}

class FormDialog extends StatefulWidget {
  @override
  _FormDialogState createState() => _FormDialogState();
}

class _FormDialogState extends State<FormDialog> {
  final _formKey = GlobalKey<FormState>();

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      Navigator.of(context).pop("true");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextFormField(
            decoration: InputDecoration(labelText: '姓名'),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return '请输入你的姓名';
              }
              return null;
            },
          ),
          SizedBox(height: 16.0),
          ElevatedButton(
            onPressed: _submitForm,
            child: Text('提交'),
          ),
        ],
      ),
    );
  }
}

说明

  1. Isolate.run()会创建独立线程执行耗时操作,主线程不受阻塞,Navigator.pop()触发的UI更新能立即生效,弹窗正常关闭。
  2. 若需在耗时操作完成后更新UI,需通过setState()或Navigator回到主线程执行,因为Isolate无法直接访问主线程的UI上下文。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:20:54