使用提供程序和快餐栏查找已停用小部件的祖先是不安全的

Posted

技术标签:

【中文标题】使用提供程序和快餐栏查找已停用小部件的祖先是不安全的【英文标题】:Looking up a deactivated widget's ancestor is unsafe using provider and snackbar 【发布时间】:2020-11-18 12:02:20 【问题描述】:

我正在使用 DismissibleWidget 从列表中删除注释。当注释被删除时,会调用一个 Snackbar 以让用户有机会撤消该操作。单击按钮后,将注释重新插入到列表中时,会出现此错误:

在处理手势时抛出以下断言: 查找已停用小部件的祖先是不安全的。 此时小部件的元素树的状态不再稳定。

    可关闭的小部件

                 Dismissible(
                    direction: DismissDirection.endToStart,
                    onDismissed: (direction)
                      var removedNote = list.notes[index];
                      Provider.of<ListProvider>(context, listen: false).removeNote(index);
    
                      Scaffold.of(context).showSnackBar(
                          SnackBar(
                            content: Text("Nota removida"),
                            action: SnackBarAction(
                              label: "Desfazer",
                              onPressed: ()
                                Provider.of<ListProvider>(context, listen: false).insertNote(removedNote, index);
                              ,
                            ),
                            duration: Duration(seconds: 3),
                          ),
                      );
                    ,
    

    ...

    提供者中的方法

    void insertNote(NoteModel note, int index)
       notes.insert(index, note);
       fileRepository.saveToFile(notes);
       notifyListeners();
    

【问题讨论】:

【参考方案1】:

我遇到了一些问题,但使用 BLoC 作为状态管理,我的解决方案是从该小部件上方获取上下文。

出了什么问题?

您试图寻找不再可用的上下文。这也是因为variable shadowing。

解决方案?

到达该小部件上方的内容。

伪颤振代码

class NameOfYourClass
    build(BuildContext context1) 
      return ListView.builder(
          itemBuilder: (context2, index) 
             return MyItem(); 
          
      );
    
   

假设您使用Dismissible 小部件关闭MyItemcontext2 将不再可用,如果您打印context2,它将看起来像这样(注意 :当MyItem 被解雇时):

SliverList(delegate: SliverChildBuilderDelegate#66afb(estimated child count: 1), renderObject: RenderSliverList#593ed relayoutBoundary=up2 DETACHED)

如您所见,该项目是树中的DETACHED。如果您打印 context1,它将看起来像这样。

NameOfYourClass

总之,不要这样做:

 Provider.of<ListProvider>(context2, listen: false).insertNote(removedNote, index);

这样做:

 Provider.of<ListProvider>(context1, listen: false).insertNote(removedNote, index);

不要使用 context1 或 context2,这是为了说明目的。

【讨论】:

如果你还不太明白,让我知道用Provider制作一个可重现的示例代码。

以上是关于使用提供程序和快餐栏查找已停用小部件的祖先是不安全的的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:查找已停用小部件的祖先是不安全的

如果添加到动画列表,Flutter 查找已停用小部件的祖先是不安全的

尝试使用谷歌地图时查找已停用小部件的祖先是不安全的

Flutter:错误是查找已停用小部件的祖先是不安全的

未处理的异常:查找已停用小部件的祖先是不安全的。如何解决这个问题?

Flutter & Navigator & ImagePicker : 为啥我可以进入下一页?查找已停用小部件的祖先是不安全的