flutter - 为什么我的 PopupMenuItem 上会出现 "Looking up a deactivated widget' 的祖先不安全”?

标签 flutter dart

我有一个 Flutter 页面/小部件,带有一个搜索框和一个从 flutter_bloc 填充的 ListView集团。
当输入文本时,我调用一个 BLOC 方法来搜索结果,并将结果呈现在一个 ListView 中。
enter image description here
当我点击 PopupMenuItemListTile我得到的项目:

enter image description here

Looking up a deactivated widget's ancestor is unsafe. At this point the state of the widget's element tree is no longer stable. To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactTpye() in the widget's didChangeDepencies() method.



如果我用 stations 的简单静态列表初始化替换 BLOC“舞蹈”变量,它工作正常。

我完全不知道该怎么办?
有人可以给我一些指点吗?

编辑 :
这是一个重现示例(仅限 Android):
https://github.com/MagnusJohansson/bloc_test
单击应用程序中的搜索图标,输入“test”作为搜索词。单击三点状菜单以触发错误(可能需要单击两次)。
如果不执行 sqlite 查询,而是返回一个静态列表(如文件/bloc/searchpresets/search_presets_bloc.dart 第 55 行中的注释所示),它工作正常。
class SearchPresetsPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _SearchPresetsPageState();
}

final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey2 =
    new GlobalKey<RefreshIndicatorState>();

final GlobalKey<ScaffoldState> scaffoldKey2 = new GlobalKey<ScaffoldState>();

final snackBar = SnackBar(
  content: Text('Added as a favorite'),
  action: SnackBarAction(
    label: 'Undo',
    onPressed: () {},
  ),
);

class _SearchPresetsPageState extends State<SearchPresetsPage> {
  final TextEditingController _filter = new TextEditingController();
  List<Station> stations = [];

  _textInputSearch() {
    if (_filter.text.length >= 2) {
      BlocProvider.of<SearchPresetsBloc>(context)
          .add(SearchPresets(_filter.text));
    }
  }

  @override
  void initState() {
    _filter.addListener(_textInputSearch);
    super.initState();
  }

  Widget buildInitialStationsInput(BuildContext context, String message) {
    return Column(children: <Widget>[
      Center(child: Text(message)),
    ]);
  }

  Widget buildLoading() {
    return Center(
      child: LinearProgressIndicator(
        value: null,
      ),
    );
  }

  Widget _buildListView() {
    return RefreshIndicator(
      key: _refreshIndicatorKey2,
      child: Column(
        children: <Widget>[
          Container(
            color: Colors.grey[300],
            alignment: Alignment.topLeft,
            child: Padding(
              padding: const EdgeInsets.all(4.0),
              child: Text(
                "${stations.length} Stations:",
              ),
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: stations != null ? stations.length : 0,
              itemBuilder: (context, index) {
                return Card(
                  child: ListTile(
                    dense: true,
                    title: Text(stations[index].name),
                    leading: IconButton(
                      alignment: Alignment.center,
                      icon: Icon(Icons.play_arrow),
                      onPressed: () async {
                      },
                    ),
                    trailing: PopupMenuButton(
                      onSelected: (value) async {
                      },
                      itemBuilder: (context) {
                        return [
                          PopupMenuItem(
                            value: 1,
                            child: Text("Add to favorites"),
                          ),
                        ];
                      },
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
      onRefresh: () async {
        BlocProvider.of<SearchPresetsBloc>(context)
            .add(SearchPresets(_filter.text));
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return BlocListener<SearchPresetsBloc, SearchPresetsState>(
      listener: (BuildContext context, SearchPresetsState state) {},
      child: Scaffold(
        key: scaffoldKey2,
        appBar: AppBar(
          actions: <Widget>[],
          title: Container(
            color: Colors.white,
            child: TextField(
              controller: _filter,
              decoration: new InputDecoration(
                  filled: true,
                  suffixIcon: IconButton(
                    icon: Icon(Icons.clear),
                    onPressed: () {
                      _filter.clear();
                      setState(() {
                        stations = [];
                        BlocProvider.of<SearchPresetsBloc>(context)
                            .add(ClearSearch());
                      });
                    },
                  ),
                  prefixIcon: new Icon(Icons.search),
                  hintText: 'Search...'),
            ),
          ),
        ),
        body: BlocBuilder<SearchPresetsBloc, SearchPresetsState>(
            builder: (BuildContext context, SearchPresetsState state) {
          if (state is InitialSearchPresetsState) {
            return buildInitialStationsInput(context,
                "Search for stations in the search box above (at least 2 characters)");
          }
          if (state is SearchPresetsLoading) {
            return buildLoading();
          }
          if (state is SearchPresetsLoaded) {
            stations = state.stations;
            return _buildListView();
          }
          if (state is SearchPresetsError) {
            return buildInitialStationsInput(
                context, state.exception.toString());
          }
          return Container();
        }),
      ),
    );
  }
}

最佳答案

这是contexts的问题.它经常发生在 Dialogs ,以及 PopMenu行为有点类似于对话框,但使用对话框您可以传递 context你想用 GlobalKey 解决这个问题并访问 contextScaffold .不幸的是,在这里这是不可能的。

尽管如此,PopMenuButton 上有一个标志似乎可以解决您的问题。 captureInheritedThemes . documentation状态:“如果为 true(默认值),则菜单将包含 InheritedThemes 的副本,例如 Theme 和 PopupMenuTheme,,它们定义在 BuildContext 上方,其中显示菜单 ”。那似乎是我们的问题,上下文的继承。

在您的 search_presets_widget.dart 文件中,在您的 PopupMenuButton 中内_buildListView方法,添加这一行:

PopupMenuButton(
  captureInheritedThemes: false, // Add this line
  ...

关于flutter - 为什么我的 PopupMenuItem 上会出现 "Looking up a deactivated widget' 的祖先不安全”?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59636507/

相关文章:

flutter - 如何在不使用 border-radius 的情况下创建弯曲的小部件

flutter - 无法将参数类型 'BoxShadow'分配给参数类型 'List<BoxShadow>'

dart - 透明背景显示白色的自定义小部件

Flutter:使用 ListTile 时未布局 RenderBox

firebase - 上载到Firebase存储失败

android - Flutter:发布失败(66)

dart - Flutter:将 ListTile 标记为在抽屉中被选中

flutter - Charts_flutter软件包中的图形中的domainFn和measureFn是什么?

firebase - 将Firebase嵌套 map 转换为List <Object>

flutter 驱动: How to check device orientation?