Dismissible confirmDismiss 结合新的路由导航导致 Flutter 崩溃

Posted

技术标签:

【中文标题】Dismissible confirmDismiss 结合新的路由导航导致 Flutter 崩溃【英文标题】:Dismissible confirmDismiss in combination with new route navigation causes Flutter crash 【发布时间】:2019-10-03 14:16:51 【问题描述】:

上下文: 我在 Flutter 中测试Dismissibles 中的ListView 时偶然发现了一次小崩溃。滑动可关闭项时,使用confirmDismiss 选项显示Dialog 以进行确认。这一切都很好,但是在测试不太可能的用例时 UI 会崩溃。页面上有几个选项可以导航到其他(命名的)路线。当轻扫可关闭的对象时,并且在动画期间点击导航到新路线的选项时,会发生崩溃。

如何复制崩溃:

    解雇被解雇的人 在随后的动画(可关闭位置的平移)中,点击一个动作,将您带到 新路线。执行此操作的时间范围很短,我在示例中对其进行了扩展。 新路由加载,UI 冻结

作为参考,这是错误信息:

AnimationController.reverse() 在 AnimationController.dispose() 之后调用

罪魁祸首是动画在它已经被释放时试图反转:

package:flutter/…/widgets/dismissible.dart:449

我尝试过的事情: 最初,我尝试在showDialog builder 中检查this.mounted,但很快意识到问题不在于那里。 另一个想法是通过使用CancelableOperation.fromFuture 来规避问题,然后在包含小部件的dispose() 方法中取消它,但这无济于事。

我能做些什么来解决或至少规避这个问题?

代码(也可以找到克隆here):

// (...)
class _DimissibleListState extends State<DimissibleList> 
  int childSize = 3;

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: ListView.builder(
        itemCount: childSize,
        itemBuilder: (context, index) 
          if (index == 0) 
            return _buildNextPageAction(context);
          
          return _buildDismissible();
        ,
      ),
    );
  

  Widget _buildNextPageAction(context) 
    return FlatButton(
      child: Text("Go to a new page"),
      onPressed: () => Navigator.of(context).pushNamed('/other'),
    );
  

  Dismissible _buildDismissible() 
    GlobalKey key = GlobalKey();

    return Dismissible(
      key: key,
      child: ListTile(
        title: Container(
          padding: const EdgeInsets.all(8.0),
          color: Colors.red,
          child: Text("A dismissible. Nice."),
        ),
      ),
      confirmDismiss: (direction) async 
        await Future.delayed(const Duration(milliseconds: 100), () );
        return showDialog(
          context: context,
          builder: (context) 
            return Dialog(
              child: FlatButton(
                onPressed: () => Navigator.of(context).pop(true),
                child: Text("Confirm dismiss?"),
              ),
            );
          ,
        );
      ,
      resizeDuration: null,
      onDismissed: (direction) => setState(() => childSize--),
    );
  

【问题讨论】:

您是否尝试过延迟导航?就像 500 毫秒后弹出一样? 嘿@danypata,这是一个有趣的思路!但是延迟并没有解决问题。现在当用户返回到带有列表视图的页面时应用程序崩溃(并且错误保持不变) 我添加了一行“await Future.delayed(const Duration(milliseconds: 100), () );”,它对我有用。感谢您提出这个问题。 【参考方案1】:

confirmDismiss 遇到了几乎相同的问题,在我的情况下,我在 confirmDismiss 中使用 (await Navigator.push()) 导航到另一个屏幕,但作为回报,我遇到了这个错误:

AnimationController.reverse() 之后调用 AnimationController.dispose()

所以为了解决我在 confirmDismiss 内部的问题,我在 confirmDismiss 之外调用了一个未来函数(没有 await ),然后在该函数调用之后添加 return true 或 false 以完成 confirmDismiss 的动画。

【讨论】:

以上是关于Dismissible confirmDismiss 结合新的路由导航导致 Flutter 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Dismissible 和 FutureBuilder 不能一起工作

Flutter Dismissible 未从树中移除

被解雇的 Dismissible 小部件仍然是颤动树的一部分

Flutter Dismissible 小部件,带有 confirmDismiss 和 showAlertDialog 停止应用程序

flutter Dismissible 可以在拖动时隐藏的widget

Dismissible confirmDismiss 结合新的路由导航导致 Flutter 崩溃