【问题标题】:Calling a method with Provider.of(context) inside of dispose() method cause "Looking up a deactivated widget's ancestor is unsafe."在 dispose() 方法中使用 Provider.of(context) 调用方法会导致“查找已停用小部件的祖先是不安全的”。
【发布时间】:2020-05-19 03:33:48
【问题描述】:

当我尝试调用 State dispose 方法中的方法时,如下所示。

  @override
  void dispose() {
    Provider.of<AppProvider>(context, listen: false).close();
    super.dispose();
  }

我知道了。

The following assertion was thrown while finalizing the widget tree:
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 dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.

When the exception was thrown, this was the stack
#0      Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> 
package:flutter/…/widgets/framework.dart:3508
#1      Element._debugCheckStateIsActiveForAncestorLookup 
package:flutter/…/widgets/framework.dart:3522
#2      Element.getElementForInheritedWidgetOfExactType 
package:flutter/…/widgets/framework.dart:3588
#3      Provider.of 
package:provider/src/provider.dart:219
#4      _MySecondPageState.dispose 
package:test_space/main.dart:138
...

这是我的示例 AppProvider

class AppProvider {
  close() {}
}

我用 AppProvider 包装了 MaterialApp

return Provider<AppProvider>(
      create: (_) => AppProvider(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomeScreen(),
        },
      ),
    );

我不知道该怎么做To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method. 我目前正在使用provider: ^4.0.2

我以前也是这样做的,在 dispose() 中使用 Provider.of(context),之前没有这个例外。这是因为新的颤振版本吗? 另外,我意识到有 deactivate() 方法,我应该使用 deactivate() 方法而不是 dispose() 方法吗?

[更新]

  AppProvider _appProvider;
  @override
  void didChangeDependencies() {
    _appProvider = Provider.of<AppProvider>(context, listen: false);
    super.didChangeDependencies();
  }

  @override
  void dispose() {
    _appProvider.close();
    super.dispose();
  }

I could also use deactivate in a certain case

  @override
  void deactivate() {
    Provider.of<AppProvider>(context, listen: false)
        .close();
    super.deactivate();
  }

【问题讨论】:

    标签: flutter dart flutter-layout


    【解决方案1】:

    您似乎正在尝试关闭 AppProvider 类中定义的内容。如果 AppProvider 类继承了 ChangeNotifier,则 change Notifier 类提供了 dispose 方法,你可以重写它,然后只在 AppProvider 类内部调用 close 函数。

    【讨论】:

    • 我没有扩展 ChangeNotifier。我不确定,但是当尝试在dispose() 中使用context 时,它会引发异常。
    • 同样的问题,对我有用。
    【解决方案2】:

    据我所知,这种行为是很久以前的事了,我通常使用after_layout来解决它:

    class MyWidget extends StatefulWidget {
      @override
      _MyWidgetState createState() => _MyWidgetState();
    }
    
    class _MyWidgetState extends State<MyWidget> with AfterLayoutMixin {
      AppProvider _appProvider;
    
      @override
      void afterFirstLayout(BuildContext context) {
        _appProvider = Provider.of<AppProvider>(context, listen: false);
      }
    
      @override
      void dispose() {
        _appProvider.close();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          // ...
        );
      }
    }
    

    【讨论】:

      【解决方案3】:

      如果您需要在离开上下文之前处置某些东西,您可以在willPopScope 中处置它

       WillPopScope(
          onWillPop: () {
             context.read<AppProvider().myController?.dispose();
             Navigator.pop(context);
             return Future.value(false);
          },
          child: ...,
       )
      

      【讨论】:

      • 这不是一个可靠的解决方案,因为 onWillPop 不会被 Navigator.pushReplacement() 或底部导航栏调用。
      猜你喜欢
      • 2021-11-15
      • 2021-11-08
      • 2020-08-08
      • 2021-07-28
      • 2021-06-03
      • 2020-12-26
      • 2022-06-26
      • 2021-04-29
      • 1970-01-01
      相关资源
      最近更新 更多