更改路线时,Flutter Provider 会多次更新

Flutter Provider updates multiple time when changing route

我使用了一个模型的 ChangeNotifierProvider,它有一个“数字”属性 和一个为其设置随机值的方法。有2条路线。在第一个中,有一个变量使用 context.selectcontext.watch(无关紧要)侦听此 属性,然后在 Text 小部件中使用。还有一个调用模型方法的按钮,该方法设置随机值。最初,如果没有屏幕发生变化,按下此按钮时,将按预期重建小部件。推送到另一条路线然后返回到第一条路线时会出现问题。如果再次按下按钮,小部件将重建两次,因为提供者出于某种原因也被更改了两次。在屏幕之间切换的次数越多,当您按下设置随机值的按钮时,小部件重建的次数就越多。下面您可以看到来自 Dart DevTools 的带有日志的屏幕截图。在这里我举了一个小例子,只是为了说明我的问题,但是在另一个项目中,不是简单的文本小部件而是带有数据的 table ,每次屏幕更改后性能的下降变得更加明显,因为对导致模型更改的用户操作的响应变得更长。

class MyModel extends ChangeNotifier {
  int _number = 0;
  int get number => _number;

  void setRandomNumber() {
    print('Set random number');
    _number = Random().nextInt(1000);
    notifyListeners();
  }
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyModel>(
      create: (context) => MyModel(),
      child: MaterialApp(
        routes: {
          '/home': (context) => MyHomePage(),
          '/second': (context) => SecondPage(),
        },
        initialRoute: '/home',
      ),
    );
  }
}
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final number = context.select<MyModel, num>((model) => model.number);
    print('REBUILD');

    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Text(number.toString()),
            TextButton(
              child: Text('Go to Page 2'),
              onPressed: () {
                print('Go to Page 2');
                Navigator.pushNamed(context, '/second');
              },
            ),
            TextButton(
              child: Text('Set Random Number'),
              onPressed: () => context.read<MyModel>().setRandomNumber(),
            ),
          ],
        ),
      ),
    );
  }
}
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: TextButton(
        child: Text('Go to Home Page'),
        onPressed: () {
          print('Go to Home Page');
          Navigator.pushNamed(context, '/home');
        },
      ),
    );
  }
}

控制台:

flutter: Set random number
flutter: REBUILT

flutter: Go to Page 2
flutter: Go to Home Page

flutter: Set random number
flutter: REBUILT
flutter: REBUILT

DevTools 中的日志

这是因为你推的时候没有弹出。你有一堆屏幕 1、屏幕 2、屏幕 1。你按下屏幕 1 上的按钮,它会执行设置的随机数函数,并通知屏幕 1 的两个实例上的听众。

在任何时候都不要在导航堆栈中出现重复屏幕通常是一个好习惯。像 auto_route 这样的包在某种程度上加强了这一点,尽管你也可以在不使用包的情况下管理它。当 popping 可以将您带到同一屏幕时,请勤奋并警惕推送。