Flutter Pageview : swiping backward calls build method on widgets in unexpected ways

Viewed 1172

Consider this simple code snippet, a snippet I wrote to reproduce my problem. It is just a pageview with 3 stateful widgets into it. (It is stand alone, you can copy-paste it and run it):

import 'package:flutter/material.dart';

void main() => runApp(new TestInherited());

class TestInherited extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        title: 'Pageview test',
        home: PageView(
          children: <Widget>[TestWidget("1"), TestWidget("2"), TestWidget("3")],
        ));
  }
}

class TestWidget extends StatefulWidget {
  final String _name;
  String get name => _name;

  @override
  TestWidgetState createState() {
    return TestWidgetState();
  }

  TestWidget(this._name);
}

class TestWidgetState extends State<StatefulWidget> {
  @override
  Widget build(BuildContext context) {
    TestWidget w = widget;
    print("building ${w._name}");
    return Center(child: Text(w._name));
  }
}

When swiping forward from page 1 to 2 to 3, you see the build methods being called nicely (due to the print statements). But when going backward, from page 3 to page 2 this does not happen for page 2. But going from 2 to 1 it is called for page 1. So:

  • 3 to 2: nothing happens
  • 2 to 1: prints "building 1"

That is a problem for me since in my project on page 3 I change stuff that influences page 2 so it needs to rebuild.

It even gets more strange when just adding a few more pages (say we have 5). Then going forward works fine, (the print happens on every page) but going backward...

  • 5 to 4: prints "building 3" (??)
  • 4 to 3: nothing
  • 3 to 2: prints "building 2"
  • 2 to 1: prints "building 1"

Can anyone explain this to me, please?

Thanks a lot for your time and help!

1 Answers

As a general rule, you should assume that nothing will be rebuilt if you want it to be rebuilt and everything will be rebuilt if you want it not to be. The model is that we rebuild everything every frame, but we have optimizations to remove rebuilds that we can prove aren't necessary.

In this case, since you never call setState, we don't really need to rebuild anything. We probably only rebuild the widgets that we discarded to save memory when they're not visible.

The TestWidget should call setState when it needs to be rebuilt. You could have page 3 send a notification to page 2 via a Listenable or some such and have page 2 use that to know when to rebuild.

Related