Reputation: 10444
I'm developing a flutter app and recognized an unexpected behavior with the state managment. I created a sample app to reproduce the behavior and you can find the code and log output below.
The app contains a simple ListView which contains 10 stateful Container (Text + Decoration). When i scroll down, each container and its container state will be created once like expected. When i scroll up again, Flutter recreates every state (but not the container widget) for each container widget which appears again on the display. I would expect that flutter would retrieve the previous state without recreating the whole state object. Am I doing something wrong here?
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key) {
print("MyHomePage constructor");
}
@override
_MyHomePageState createState() {
print("createState");
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
_MyHomePageState() {
print("_MyHomePageState contructor");
}
void initState() {
super.initState();
print("_MyHomePageState initState");
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemBuilder: (context, index) {
return ContainerWidget(index, key: ValueKey(index));
},
itemCount: 10,
));
}
}
class ContainerWidget extends StatefulWidget {
int index;
ContainerWidget(this.index, {key}) : super(key: key) {
print("ContainerWidget constructor for index $index");
}
@override
State<StatefulWidget> createState() {
print("ContainerWidget createState for index $index");
return _ContainerState();
}
}
class _ContainerState extends State<ContainerWidget> {
_ContainerState() {
print("_ContainerState constructor");
}
void initState() {
super.initState();
print("_ContainerState initState for index ${widget.index}");
}
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("Index: ${widget.index}"),
),
height: 200,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.green),
),
),
);
}
}
Log-Output:
I/flutter (22400): createState
I/flutter (22400): _MyHomePageState contructor
I/flutter (22400): _MyHomePageState initState
I/flutter (22400): ContainerWidget constructor for index 0
I/flutter (22400): ContainerWidget createState for index 0
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 0
I/flutter (22400): ContainerWidget constructor for index 1
I/flutter (22400): ContainerWidget createState for index 1
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 1
I/flutter (22400): ContainerWidget constructor for index 2
I/flutter (22400): ContainerWidget createState for index 2
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 2
I/flutter (22400): ContainerWidget constructor for index 3
I/flutter (22400): ContainerWidget createState for index 3
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 3
I/flutter (22400): ContainerWidget constructor for index 4
I/flutter (22400): ContainerWidget createState for index 4
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 4
I/flutter (22400): ContainerWidget constructor for index 5
I/flutter (22400): ContainerWidget createState for index 5
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 5
I/flutter (22400): ContainerWidget createState for index 1
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 1
I/flutter (22400): ContainerWidget createState for index 0
I/flutter (22400): _ContainerState constructor
I/flutter (22400): _ContainerState initState for index 0
Upvotes: 7
Views: 2069
Reputation: 276881
This is expected, as the items are unmounted when they leave the screen.
If you don't want that, you'll want to use what we call "keep alive".
You can do so by adding a mixin to your State
class:
class _MyHomePageState extends State<MyHomePage> with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
// ...
}
Upvotes: 7