153 votes

setState() appelé après dispose()

Lorsque je clique sur le bouton surélevé, le sélecteur de temps s'affiche. Maintenant, si j'attends 5 secondes et que je confirme l'heure, cette erreur se produit. setState() appelé après dispose()

Je vois littéralement dans la console comment flutter met à jour les widgets parents, mais pourquoi ? - Je ne fais rien, j'attends juste 5 secondes ! Cet exemple fonctionnera dans un projet normal, mais dans mon projet, qui est beaucoup plus complexe, il ne fonctionnera pas car flutter met à jour les états pendant que j'attends... Qu'est-ce que j'ai fait de mal ? Quelqu'un a-t-il une idée de ce qui pourrait expliquer que flutter mette à jour les états de manière aléatoire dans mon projet plus complexe et pas dans un projet simple ?

[MISE À JOUR] J'ai vérifié que la mise à jour se fait à partir du niveau où se trouvent ma TabBar et ma TabBarView. Cela pourrait-il avoir un rapport avec l'élément " avec TickerProviderStateMixin "dont j'ai besoin pour la vue de la barre d'onglets ? Cela pourrait-il être dû au fait que l'application se rafraîchit régulièrement et de manière aléatoire ?

 class DateTimeButton extends State<DateTimeButtonWidget> {
  DateTime selectedDate = new DateTime.now();

  Future initTimePicker() async {
    final TimeOfDay picked = await showTimePicker(
      context: context,
      initialTime: new TimeOfDay(hour: selectedDate.hour, minute: selectedDate.minute),
    );

    if (picked != null) {
      setState(() {
        selectedDate = new DateTime(selectedDate.year, selectedDate.month, selectedDate.day, picked.hour, picked.minute);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return new RaisedButton(
      child: new Text("${selectedDate.hour} ${selectedDate.minute}"),
      onPressed: () {
        initTimePicker();
      }
    );
  }
}

0 votes

"avec TickerProviderStateMixin" - oui, je pense que cela entraîne la reconstruction de votre widget.

360voto

Ganapat Points 1575

Vérifiez simplement la propriété booléenne mounted de la classe d'état de votre widget avant d'appeler setState() .

if (this.mounted) {
  setState(() {
    // Your state change code goes here
  });
}

Ou une approche encore plus propre Remplacer setState dans votre StatelfulWidget classe.

class DateTimeButton extends StatefulWidget {
  @override
  void setState(fn) {
    if(mounted) {
      super.setState(fn);
    }
  }
}

18 votes

Cela empêche juste de définir l'état, mais ne résout pas le problème de ne pas être capable de définir l'état.

1 votes

@temirbek Je ne suis pas sûr de votre cas d'utilisation, le but de cette condition if est exactement d'arrêter d'essayer de définir l'état une fois que le widget n'est pas monté, ce qui signifie que le widget n'existe pas dans la hiérarchie des widgets à l'écran.

1 votes

Ok, mon cas d'utilisation est que l'écran A appelle l'écran B et attend un résultat. L'écran B renvoie le résultat, mais à ce moment-là, l'écran A est recréé, et l'ancien écran qui attendait le résultat est démonté. Mais j'ai besoin de définir l'état de l'écran A avec la valeur renvoyée par l'écran B.

45voto

Günter Zöchbauer Points 21340

Si c'est un comportement attendu que le Future complète lorsque le widget a déjà été disposé, vous pouvez utiliser

if (mounted) {
  setState(() {
    selectedDate = new DateTime(selectedDate.year, selectedDate.month, selectedDate.day, picked.hour, picked.minute);
  });
}

5 votes

Je recommande docs.flutter.io/flutter/widgets/State/mounted.html au lieu d'utiliser votre propre membre.

1 votes

Merci, mon pote. Cela a sauvé ma journée (et même ma semaine) :D

0 votes

@Gunter, comment pouvons-nous appeler setState avant super.dispose() ; dans la fonction dispose(). Cela ne fonctionne pas pour moi et j'obtiens un message d'erreur comme 'package:flutter/src/widgets/framework.dart' : Failed assertion : line 4263 pos 12 : '_debugLifecycleState != _ElementLifecycle.defunct' : n'est pas vrai. J'utilise déjà if (monté) { setState(() {}) ; } Veuillez me dire quel est le problème. Merci beaucoup.

23voto

Rahul Mahadik Points 2605

Il suffit d'écrire une ligne avant setState()

 if (!mounted) return;

et ensuite

setState(() {
      //Your code
    });

12voto

teteArg Points 124

J'ai eu le même problème et j'ai résolu en changeant l'ordre d'appel du super constructeur sur initState() :

Mauvais code :

@override
  void initState() {
    foo_bar(); // in foo_bar i call setState();
    super.initState(); // state initialization after foo_bar()
  }

Le bon code :

@override
  void initState() {
    super.initState();
    foo_bar(); // first call super constructor then foo_bar that contains setState() call
  }

8voto

DimarBorda Points 21

Monté

// First Update data 

if (!mounted) { 
      return;
 }
setState(() { }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X