当 Flutter 中的全局变量更改(异步)时更新小部件

Posted

技术标签:

【中文标题】当 Flutter 中的全局变量更改(异步)时更新小部件【英文标题】:Updating a widget when a global variable changes (Async) in Flutter 【发布时间】:2020-05-25 17:52:30 【问题描述】:

我对 Flutter 还很陌生,我发现自己陷入了我挖的坑。

我想要完成的事情很简单。我有一个全局变量。假设var PlayerPointsToAdd。然后我有这个有状态的小部件,它应该在每次这个全局变量不为零时更新自己。我希望能够从另一个小部件调用addPointsToPlayer()

到目前为止,我对有状态小部件的理解以setState(()) 结尾,我只能在有状态小部件本身内部调用它。

下面的代码位于有状态小部件内的容器内。每当按下此按钮时,它都会根据PlayerScoreBoard.add() 返回的新列表调用 setState。

...
child: RaisedButton(
                        onPressed: () 
                          setState(() 
                            if (PointsToAddPlayer != 0) 
                              for (int i = 0; i < PointsToAddPlayer; i++) 
                                PlayerScoreBoard.add(new Icon(
                                    Icons.check_circle_outline,
                                    size: 11));
                              
                              PointsToAddPlayer = 0;
                            

我一直在阅读文档并在 YouTube 上观看 Flutter 视频,所以请不要忽略这个问题。我真的很难理解这一点。

我认为我必须使用 Streams 来执行此操作。它们看起来有点复杂,但如果这是我使用它们的唯一方法。这是否意味着我应该创建一个全局变量,最好是一个包含变量的类,并将它的变量流式传输到变量更新时需要更新的每个其他小部件。因此,此 ScoreBoard 小部件必须侦听来自全局类的 Stream 并自行更新。这是否允许我更改全局类中的变量并将相应的小部件自动更新为新状态?这是否意味着每个依赖于自身外部变量的小部件都必须监听流?我真的很感谢 ELI5 对 Stateful Widgets 和 Streams 之间的关系。

而且因为这个全局数据会一遍又一遍地更新很多次,所以使用 Future 是不可能的。

非常感谢。

我误说是全局类变量。我的意思是说地图之类的东西,在那里我可以有gameData.PlayerPointsgameData.turn 之类的东西。

【问题讨论】:

【参考方案1】:

你可以试试ValueListenableBuilder。

import 'package:flutter/material.dart';

final playerPointsToAdd =
    ValueNotifier<int>(0); //TODO 1st: ValueNotifier declaration

void main() => runApp(TestApp());

class TestApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) => MaterialApp(
        routes: 
          '/': (context) => HomePage(),
        ,
      );


//TODO you can use StatelessWidget either
class HomePage extends StatefulWidget 
  @override
  _HomePageState createState() => _HomePageState();


class _HomePageState extends State<HomePage> 
  @override
  Widget build(BuildContext context) => Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              RaisedButton(
                // TODO 3rd: change the value
                onPressed: () => playerPointsToAdd.value++,
                child: Text('Increase'),
              ),
              ValueListenableBuilder(
                //TODO 2nd: listen playerPointsToAdd
                valueListenable: playerPointsToAdd,
                builder: (context, value, widget) 
                  //TODO here you can setState or whatever you need
                  return Text(
                      //TODO e.g.: create condition with playerPointsToAdd's value
                      value == 0
                          ? 'playerPointsToAdd equals 0 right now'
                          : value.toString());
                ,
              ),
              RaisedButton(
                onPressed: () => playerPointsToAdd.value--,
                child: Text('Decrease'),
              ),
            ],
          ),
        ),
      );



【讨论】:

哇。我不知道这存在。我希望有更多关于此类事情的教程,而不是流和期货。我知道 Streams 非常重要,但这实现起来非常简单,这正是我所需要的。我唯一想不通的是如何让 ValueListenableBuilder 监听一个 Map,而不是一个 int。但是创建单独的变量到目前为止工作得很好。非常非常感谢! 如果要监听 Map,请将 ValueNotifier 声明更改为 ValueNotifier&lt;Map&lt;String, dynamic&gt;&gt; 并在值更改后通知侦听器 playerPointsToAdd.notifyListeners();。这不是最好的解决方案,因为方法 notifyListeners 受到保护,有时会出现令人惊讶的行为,但它可以工作并且很常用。仅供参考:将来您可以使用BLoC 而不是流 - 编码要简单得多:) 我正在尝试使用 ValueNotifier&lt;List&gt; 在不同的 dart 文件之间进行描述,但它没有渲染我的构建器。我正在从page1 更新一个全局项目变量,该变量放在page2 上,我的ValueNotifier 放在page3 上。有人知道为什么我的构建器不渲染吗? (只是为了确保一切按预期工作,当我手动渲染我的页面时,值是更新的)。 @genericUser,用minimal, reproducible example 发布您自己的问题。这样我们就更容易提供帮助了:) 谢谢@Owczar,但我已经以不同的方式实现了;)

以上是关于当 Flutter 中的全局变量更改(异步)时更新小部件的主要内容,如果未能解决你的问题,请参考以下文章

全局变量更新 AJAX POST

Flutter:当列表数据更改时,getx 控制器未更新。我如何确保添加的每个列表,GetX 控制器都知道这一点?

如何取消设置全局变量。

如何在flutter中将token设置为全局变量?所以我可以随时随地访问令牌

Flutter StreamBuilder中使用的Firestore快照在数据更改时永远不会更新

Flutter:Getx Controller中的异步函数在初始化时不起作用