【问题标题】:How to dispose of my Stateful Widget completely?如何完全处理我的 Stateful Widget?
【发布时间】:2019-02-16 16:58:54
【问题描述】:

我调用我的有状态小部件页面并从服务器获取一些信息。如果没有找到信息,它会警告用户没有任何信息。 从抽屉后退按钮,我回到上一页。如果我快速地来回重复,我的 IntelliJ IDE 中的控制台消息会出现错误;

E/flutter (22681): [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
E/flutter (22681): setState() called after dispose(): _BillsPayWaterState#66be5(lifecycle state: defunct, not mounted)
E/flutter (22681): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. The preferred solution is to cancel the timer or stop listening to the animation in the dispose of the () callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (22681): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose of ().
E/flutter (22681): #0      State.setState.<anonymous closure> 

在我的 statefull 小部件中,我有 @override void initState(),我也有 @override void dispose()

我的问题是当我使用抽屉后退按钮时,我怎样才能完全处置我的 Stateful Widget?

这是小部件的调用

onTap: () {
Navigator.push(
  context,
  SlideRightRoute(widget: new BillsWaterPay(“S02")),
);
}

这就是 BillsWaterPay 小部件

List<List<dynamic>> _userAskBills;

// TODO: KURUM KODU - SABIT TELEFON
String _kurumKodu = "";
String _noDataText = "";

class BillsWaterPay extends StatefulWidget {
  final String title;

  BillsWaterPay(this.title);

  @override
  _BillsWaterPayState createState() =>
      _BillsWaterPayState();
}

class _BillsWaterPayState extends State<BillsWaterPay> {

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _kurumKodu = widget.title;
    _userAskBills;
    _noDataText;
    _loadEverything();
}

Future _loadEverything() async {
    await _getDataFromServer();
}

Future _getDataFromServer() async() {
    …
    …
    if no data
        setState
            _noDataText = “No Data”;  // In here I get an error setState called after dispose

}


@override
void dispose() {
  super.dispose();
      _kurumKodu = widget.title;
    _userAskBills;
    _noDataText;
}

【问题讨论】:

  • 我们需要查看您的小部件的代码。如果您注册事件处理程序,则需要单独取消注册它们。没有明确的方式来处理你的小部件,你只需准备它以便 Dart 可以处理它。
  • @Günter 我更新了我的问题。查看我收到错误的 Future _getDataFromServer() async() 行。
  • 有一个ongoing discussion regarding this on github。如果您认为应该在 Flutter 中修复,请表达您的支持

标签: flutter dispose setstate stateful


【解决方案1】:

我认为问题是由于在处理小部件后服务器的响应到达造成的。

在调用setState 之前检查小部件是否已安装。这应该可以防止您看到的错误:

// Before calling setState check if the state is mounted. 
if (mounted) { 
  setState (() => _noDataText = 'No Data');
}

【讨论】:

  • 谢谢,如果(挂载)是什么意思?如果装真假我该怎么办?在新的 BillsWaterPay(“S02”) 中,“S02”总是不同的,每个不同的参数我必须得到不同的结果。如何安装对我有帮助?
  • 如果mountedfalse,不要调用setState。这意味着小部件不是渲染树的一部分。
  • 谢谢。当我调用 SlideRightRoute(widget: new BillsWaterPay(“S02”)) 时,我不是在创建一个新的小部件吗?并且 void dispose() 我假设我处置了旧的小部件。那么为什么小部件不是渲染树的一部分? 我在哪里可以获得这方面的详细信息?
  • 我没有说它永远不是渲染树的一部分,只是当服务器的响应到达时不是。此时,您的代码可能已经从父小部件上的 setState 创建了一个新实例(主要是推测和一般信息,因为您的问题没有提供太多细节)。这就是为什么从小部件中发出服务器请求通常是一个坏主意的原因。至少响应应该被缓存在小部件之外,这样当请求相同的数据时,它实际上是从缓存中使用的,而不是再次从服务器获取。
  • 非常感谢亲爱的冈特。你节省了我的 3 个小时,成就了我的一天 :)
【解决方案2】:

由于异步处理小部件后,当我们调用setState() 时会显示上述异常。

使用flutter的属性处理这个=>mounted

mounted 告知小部件的可用性。

...
if (mounted) {
    setState(() {
        ...
    });
}
...

【讨论】:

    猜你喜欢
    • 2021-06-08
    • 1970-01-01
    • 2018-01-28
    • 2021-09-26
    • 1970-01-01
    • 2023-01-24
    • 2020-06-29
    • 1970-01-01
    • 2022-12-02
    相关资源
    最近更新 更多