在Dart中的全局变量

133

我尝试创建一个Dart单页应用程序。

我创建了第一个自定义元素(custom-application),其中包含整个应用程序。它有一个容器,用于呈现视图。还有一个侧边导航,其中包含用户信息,并在用户登录时更新。

我想在视图之间共享信息。 如何在custom-application中定义全局变量并能够与其他视图共享?

例如,当您启动应用程序时,您未经身份验证。当您调用/login(login-view)时,您将拥有一个登录表单。我希望,在您登录应用程序时,custom-application元素会存储由嵌套视图login-view加载的用户信息并更新侧边导航。

这种做法可行吗?

7个回答

282

只需创建一个库文件,并在其中为需要的全局变量创建字段。在需要访问这些字段的任何地方导入此库。

app.dart

import 'globals.dart' as globals;

main() {
  globals.isLoggedIn = true;
}

组件1.dart

import 'globals.dart' as globals;

class MyComponent {
  view() {
    if(globals.isLoggedIn) {
      doSomething();
    else {
      doSomethingElse();
    }
  }
}

globals.dart

library my_prj.globals;

bool isLoggedIn = false;

您还可以


4
我已经成功地使用观察者模式将全局变量转化为可观察对象,它运行得非常好。再次感谢您。 - T00rk
2
抱歉,我的评论有点脱离上下文了。从我进行的有限测试来看,当全局变量从compute执行的回调函数中访问时,似乎不起作用。等我有时间了,我会将其作为一个正式的问题提出来。 - hunter
5
library my_prj.globalsglobals.dart 文件中是做什么用的? - Fadhil Ahmad
5
在早期Dart版本中,那个库声明是强制性的,但最终变成了可选项,我认为现在没有人再使用它了。每个不是部分文件的Dart文件都需要一个唯一的库声明。如果没有显式添加,它将从文件名+路径派生出来。 - Günter Zöchbauer
1
@GünterZöchbauer 确实,库语句是不必要的。我刚试着从代码中删除它,但“编辑队列已满”。 - Ian
显示剩余5条评论

27

你可以创建一个类

myColors.dart

class AppColors {

  static var primary = Colors.blue;
}

并导入您的类

import 'package:myapp/.../myColors.dart';

并使用AppColors.primary进行访问。


1
这真的很简单! - Reive
4
在Dart中,不建议使用静态变量来访问和更新变量。因为静态变量可能会在跨文件时丢失它们的数据(参见 https://dev59.com/3VcO5IYBdhLWcg3weBWZ)。 - Siddy Hacks

17

我创建了一个名为my-globals.dart的dart文件,我可以在其中定义我的全局变量。

就像这样:

library globals;

int globalInt = 0;
bool globalBoolean = true;
String globalString = "";
double globalDouble= 10.0;

这就是整个 dart 文件。

然后,在同一个目录或文件夹中,我可以创建其他类,并通过导入 my-globals.dart as globals 来访问我的全局变量。我们来创建一个扩展 StatefulWidget 的类。在那里,我们将通过按下 Flatbutton 来更改名为 globalInt 的全局变量的值。

import 'package:flutter/material.dart';
import 'my-globals.dart' as globals;

class OtherClass extends StatefulWidget {
  OtherClass({Key key}) : super(key: key);

  @override
  _OtherClassState createState() => _OtherClassState();
}

class _OtherClassState extends State<OtherClass> {
  @override
  Widget build(BuildContext context) {
    return Container(
       child: FlatButton(
         color: Colors.blue,
         textColor: Colors.white,
         onPressed: () {
            setState(() {globals.globalInt++;});
            print(globals.globalInt);
         },
       ),
    );
  }
}
你看,我只需输入globals.再加上库中所包含的变量名称,就可以访问我想要的变量。希望这个例子能够帮助更好地理解如何使用globals库。

5

++++ 2019年7月更新 ++++

我编写了一个集成Flutter全局配置的包。

EZ Flutter是一个小型框架,包含了许多有用的小部件、包和其他内容。其目标是从头开始提供标准功能。EZ Flutter支持管理不同的配置文件,这些文件可以在应用程序内部访问。

Github: https://github.com/Ephenodrom/EZ-Flutter

dependencies:
  ez_flutter: ^0.2.0

查看文档以了解如何使用不同的配置。

https://github.com/Ephenodrom/EZ-Flutter/blob/master/documentation/APPLICATION_SETTINGS.md

++++ 旧答案 ++++

我也遇到了全局变量的问题。因此,我需要为每个应用程序版本(dev / prod)提供不同的配置,并且我不希望将配置写在main_dev.dart或main_prod.dart文件中。

我编写了一个简单的Flutter包,用于处理具有分离配置文件并在应用程序启动时加载它们的情况。然后,在您的应用程序的每行代码中都可以使用该配置。

https://github.com/Ephenodrom/Flutter-Global-Config

如何使用:

在 assets/cfg 目录下创建一个名为 $file.json 的 json 文件。

将 assets/cfg 添加到您的 pubspec.yaml 文件中。

在应用程序启动时加载不同的配置文件:

import 'package:flutter/material.dart';
import 'package:global_configuration/global_configuration.dart';

void main() async{
  await GlobalConfiguration().loadFromAsset("app_settings");
  await GlobalConfiguration().loadFromAsset("env_dev_settings");
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  ...
}

使用您的应用程序中的配置:
import 'package:flutter/material.dart';
import 'package:global_configuration/global_configuration.dart';

class CustomWidget extends StatelessWidget {

    CustomWiget(){
        // Access the config in the constructor
        print(GlobalConfiguration().getString("key1"); // prints value1
    }

    @override
     Widget build(BuildContext context) {
        // Access the config in the build method
        return new Text(GlobalConfiguration().getString("key2"));
     }
}

2

你所需要做的就是创建一个类似于 "constants.dart" 的文件。

import '...materials.dart';

const Color baseColor = Color(0XFF353535);

并且像这样使用。
import '...constants.dart';
.......
......


....
Container(
color: baseColor,
.....

),


2
这个问题是关于变量而不是常量的。 - ALEXANDER LOZANO

0

基于库的想法,这里提供一种方法来向从其他小部件调用的映射中添加任何类型的“键入”全局变量。这样,您就不必预先声明这些变量。如果变量不存在,则通过appDataSet将其添加到映射中。 因此,在像复选框这样的小部件中,您可以在setState()函数中添加例如:appDataSet('aCheckBox',value); 如果映射中不存在aCheckBox,则会添加它,并且该值将与value一起加载(在本例中为布尔值)。

library my_prj.globals;

Map appData = Map<String,dynamic>();

void appDataSet(String key, dynamic value) {
  if (!appData.containsKey(key))
    appData.putIfAbsent(key, () => value);
  else
    appData.update(key, (dynamic) => value);
  print(appData);
}

dynamic appDataGet(String key) {
  if (appData.containsKey(key))
    return (appData.putIfAbsent(key, () => {}));
  else
    return (null);
}

-2

全局变量通常不被看好。Flutter 推荐的解决方案是使用 provider 库。它只是一个小部件,您可以将其插入到小部件树中的某个高处,并给它一些值(对象、类)来保存。然后您可以在其他小部件中深入访问该值。

与全局变量相反,您可以修改由 provider 存储的值,深层次的小部件将重新渲染。

pub.dev/provider

存储数值

  Widget build(BuildContext context) {
    String someValue = '5';
    return Provider(
            create: (_) => someValue),
            child: SafeArea(...)
    );
  }

获取值:

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
      setState(() {
        value5 = context.read<String>();
      });
    });
  }

initState()中添加setState不是一个好的做法,这会在加载后对整个StatefulWidget范围进行不必要的重建。我认为直接将其绑定到value5上而不使用WidgetsBindingsetState会更好。 - GhoSt
另外,我认为最好在didChangeDependency中绑定提供程序值,而不是在initState中绑定,以确保上下文随时可用。 - GhoSt
当涉及到全局变量时,我们使用它来存储诸如API密钥或CSRF令牌之类的内容,这些内容将在各个地方使用。我们不需要将它们存储在某种小部件中,因为它们不会改变向用户显示的内容。 - Daniel Wu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接