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?
Sample code:
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
Stateful Widgets: The widgets whose state can be altered once they are built are called stateful Widgets. These states are mutable and can be changed multiple times in their lifetime. This simply means the state of an app can change multiple times with different sets of variables, inputs, data.
Why is the build method on State, and not StatefulWidget? Putting a Widget build(BuildContext context) method on State rather than putting a Widget build(BuildContext context, State state) method on StatefulWidget gives developers more flexibility when subclassing StatefulWidget.
You can call YourStateClass. initState() to revert to its original initialized state. Also make sure that when you construct your state, you will want to initialize all of your variables in the void initState() function.
There are multiple reasons : Widgets are immutable. Since the Stateful widget extends Widget it, therefore, must be immutable too. Splitting the declaration into two classes allows both the Stateful widget API to be immutable and State to be mutable.
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;
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With