简体   繁体   中英

DEBUG HELP: Flutter StatefulWidget doesn't maintain state(s) after scrolled out of view

I'm playing around with a simple app to learn Flutter. This is the structure of the UI:

app -- MaterialApp -- HomeScreen (stateful) |- ListView -- PlaceWidget (stateful) |- ListTile

The PlaceWidget object basically builds and returns a ListTile; its only additional duty is to keep track of the favorited state and builds the UI of the ListTile accordingly.

The source code is here , including two files:

  • main.dart for the entire app, and
  • places.dart for the http request

This is how the app behaves: https://gfycat.com/FineBelovedLeafhopper


On the surface, it looks as though the states of the objects are lost when scrolled out of view, but a bit of debug logging tells me otherwise.

Suppose I favorite Oto Sushi then scroll it off-screen but keep a pointer to the state object, the object's favorited state will still be true . The object itself (of class _PlaceWidgetState ), however, is reported to be defunct, not mounted .
I can no longer interact with that object. If I tap Oto Sushi one more time, it'll create a new state object and set that object's favorited state to true just like before.

As long as I do not scroll Oto Sushi off-screen, I can unfavorite it and things behave normally.

I managed to find similar problems with TextInputField and ExpansionTile (eg this question ), but I have no idea how to translate the solutions to those problems to this one.

So, architecture discussions aside, the cause of your problem is in how you are constructing the State objects. By passing the data through the constructor you are ensuring that every time your widgets are rebuilt, their state is reset.

 class PlaceWidget extends StatefulWidget {
  @override
  _PlaceWidgetState createState() {
    return new _PlaceWidgetState(place, false); // woops, always unchecked
  }

  final Place place;
  PlaceWidget(this.place, {Key key}) : super(key: key);
}

class _PlaceWidgetState extends State<PlaceWidget> { ... }

Instead of doing this, use the widget getter inside of your state widget to get access to the place member. Also make sure you only initialize your checked state inside of the State widget - or get it from some external source here.

class _PlaceWidgetState extends State<PlaceWidget> {
  bool _isChecked = false; // only store state in State

  Widget build() {
   final Place place = widget.place;
   // build your stuff.
  }
}

Now the reason your widget keeps getting rebuilt is that in a ListView , offscreen widgets may be destroyed - it is designed for very large lists. To prevent this, you can also use the KeepAlive widget.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM