161

What's the best programming practice to create a constant class in Flutter to keep all the application constants for easy reference?

I know that there is const keyword in Dart for creating constant fields, but is it okay to use static along with const, or will it create memory issues during runtime?

class Constants {
  static const String SUCCESS_MESSAGE = "You will be contacted by us very soon.";
}

This question is not only based on getting a proper structure but also on knowing how to save resources and memory leakage prevention while creating constants.

Manoj Perumarath
  • 9,337
  • 8
  • 56
  • 77

12 Answers12

239

My preferred solution is to make my own Dart library.

Make a new dart file named constants.dart, and add the following code:

const String SUCCESS_MESSAGE=" You will be contacted by us very soon.";

Edit: 99% of the time you don't need to explicitly name your dart libraries with a statement like library library_name; at the top of your file, and you probably shouldn't (reference).
Even if you leave out this line your file will still be library! It will just be implicitly named.

Then add the following import statement to the top of any dart file which needs access to the constants:

import 'constants.dart' as Constants;

Note if constants.dart is in different directory then you will need to specify the path to constants.dart in your import statement.

EDIT: Use lowercase_with_underscores when specifying a library prefix.

In this example:

enter image description here

You could use a relative path:

import '../assets/constants.dart' as constants;

Or an absolute path from the lib directory:

import 'package:<your_app_name>/assets/constants.dart' as constants;

Now you can easily access your constants with this syntax:

String a = Constants.SUCCESS_MESSAGE;
Jahn E.
  • 1,228
  • 3
  • 6
  • 21
Anirudh
  • 2,648
  • 2
  • 13
  • 16
  • 2
    My approach is very similar: I just have a folder called "constants" with a bunch of files inside and the "constants.dart" as the import file, then in the lib root itself I have "constants.dart" with a line inside `export "constants/constants.dart";`. Then I just created a shortcut snippet in VSCode with prefix "_iconst" that creates such import for me `import 'package:/constants.dart' as Constants;` – nt4f04und Apr 11 '20 at 00:01
  • 1
    This approach doesn't work for me. 'constants.dart' without path will not be found because it's not in the same folder. Not even when it's located directly in /lib. – madlick71 Jul 08 '20 at 08:56
  • 2
    What if you want to import a single constant like JS? – Nikhil Pathania Jul 12 '20 at 10:21
  • what is the use of `library constants;` – emkarachchi Oct 02 '20 at 05:55
  • It let's dart know that the file is a library https://stackoverflow.com/questions/10157598/how-to-create-libraries-for-dart – Anirudh Oct 02 '20 at 05:58
  • should I create multiple libraries for eg. for colors, strings, sizes and other stuff like api related ? – akshay bhange Oct 14 '20 at 15:24
  • I am doing this and using the constant in a switch statement and get Case expressions must be constants – user3808307 Oct 21 '20 at 18:06
  • @Anirudh this would work exactly as is, without the `library constants;` line. What extra stuff does that do? – Abhishek Jain Oct 28 '20 at 13:14
  • library is a dart keyword that tells dart the file you are declaring is a library. Which is why dart lets you import the file into other files. This answer talks a bit more about this: https://stackoverflow.com/questions/12951989/how-to-reference-another-file-in-dart – Anirudh Oct 28 '20 at 21:46
  • Turns out library constants; does pretty much nothing – Anirudh Dec 17 '20 at 04:27
  • 2
    Useful answer, however, it is recommendet to use `lowercase_with_underscores` when specifying a library prefix. – Jahn E. Dec 08 '21 at 10:47
  • 1
    SCREAMING_CAPS no longer recommended style: https://dart.dev/effective-dart/style#prefer-using-lowercamelcase-for-constant-names – sonjz Jun 29 '23 at 16:02
90

EDIT

Now that the flag --dart-define has been added to the different command lines of Flutter, the following answer no-longer applies.

Instead just declare constants wherever you want, and potentially refer to other answers.


While there are no technical issues with static const, architecturally you may want to do it differently.

Flutter tend to not have any global/static variables and use an InheritedWidget.

Which means you can write:

class MyConstants extends InheritedWidget {
  static MyConstants of(BuildContext context) => context. dependOnInheritedWidgetOfExactType<MyConstants>();

  const MyConstants({Widget child, Key key}): super(key: key, child: child);

  final String successMessage = 'Some message';

  @override
  bool updateShouldNotify(MyConstants oldWidget) => false;
}

Then inserted at the root of your app:

void main() {
  runApp(
    MyConstants(
      child: MyApp(),
    ),
  );
}

And used as such:

@override
Widget build(BuilContext context) {
  return Text(MyConstants.of(context).successMessage);
}

This has a bit more code than the static const, but offer many advantages:

  • Works with hot-reload
  • Easily testable and mockable
  • Can be replaced with something more dynamic than constants without rewriting the whole app.

But at the same time it:

  1. Doesn't consume much more memory (the inherited widget is typically created once)
  2. Is performant (Obtaining an InheritedWidget is O(1))
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • 3
    "Flutter tend to not have any global/static variables and use an InheritedWidget". Where is that said though? I come from traditional Java Development and this feels incredibly hacky ... – Wecherowski Jan 02 '20 at 20:46
  • 2
    @Wecherowski it's implicit by what Flutter exposes. There are very, very few static variables when opposed to InheritedWidgets. You can use whatever you like though. – Rémi Rousselet Jan 15 '20 at 12:57
  • 4
    "Flutter tend to not have any global/static variables and use an InheritedWidget". Constants are per definition no variables. Therefore I do not understand, what you try to solve with an InheritedWidget. – tvw Jan 17 '20 at 23:24
  • 1
    @tvw "constants" also includes things like "isInDebugMode" or the current platform. They are constants for a build, but may change between builds. Using InheritedWidgets allows an easier workflow when dealing with these, such as mocking their value, or changing it live in dev mode. – Rémi Rousselet Jan 17 '20 at 23:33
  • This seems to be not so suitable for Blocs, which I use a lot. With this approach, I have to share/pass the context(s) to my Blocs, no? – Magnus Johansson Jan 25 '20 at 15:51
  • 3
    Dart documentation says explicitly "AVOID defining a class that contains only static members." https://dart.dev/guides/language/effective-dart/design – Hyung Tae Carapeto Figur Aug 12 '20 at 22:23
  • 2
    But on the same page, it also said this "However, this isn’t a hard rule. With constants and enum-like types, it may be natural to group them in a class." This means that it's ok to store static string or color variables inside a class – Tek Yin Apr 03 '21 at 17:22
  • @Hyung Tae Carapeto Figur - Yes, you should use top level constants instead. – ciaranodc Feb 28 '23 at 16:46
38

Referring to https://dart.dev/guides/language/effective-dart/design

It's a good practice to group, constants and enum-like types in a class like below:

enter image description here

Auto import is straightforward in Android Studio, where you can type the class name Color, and Android Studio will be able to suggest auto import of Color class.

ChinLoong
  • 1,735
  • 24
  • 26
  • 2
    True. The fact my IDE doesn't recognise it is a fat downer. Not being able to auto import and having to type 'import' is just not done in this time. – html_programmer Feb 09 '21 at 19:08
  • I used the most voted and autocomplete also shows up in Android studio – West Nov 09 '21 at 01:09
18

I've noticed a little confusion across the answers here, so I thought I would try to clear a few things up.

Dart/Flutter guidelines suggest not creating classes that only contain static members, namely because it isn't necessary. Some languages, such as Java or C# will not allow you to define functions, variables, or constants outside of a class, but Dart will. Therefore, you can simply create a file such as constants.dart that contains the constants that you want to define.

As noted by @Abhishek Jain, the library keyword is not required for this method to work. The library keyword is used for libraries that will be published for use in other projects, although it can be used along with part and part of to break a single library up across multiple files. However, if you need that, then your needs are probably beyond the scope of OP's question.

As pointed out by @ChinLoong, it is technically acceptable to create a class that groups related constants and enum-like types. It should be noted however that this demonstrates an exception to the guideline as it is not a hard rule. While this is possible, in Dart, it is frowned upon to define a class that is never instantiated. You'll notice that the Dart Color class that defines Color constants has a constructor which excepts an integer value, allowing instantiation for colors not defined by a constant.

In conclusion, the approach that best adheres to the Dart guidelines is to create a constants.dart file or a constants folder containing multiple files for different constants (strings.dart, styles.dart, etc.). Within the constants.dart file, define your constants at the top level.

// constants.dart
 
const String SUCCESS_MESSAGE=" You will be contacted by us very soon.";

...

Then, import the file wherever the constants need to be used and access directly via the constant's name.

Lee3
  • 2,882
  • 1
  • 11
  • 19
8

For all constants, just create constants.dart file under lib folder or lib/util folder, then keep all constant variables as follows :

 const SUCCESS_MESSAGE=" You will be contacted by us very soon.";

 // Api related 
 const apiBaseURL = "https://baseurl.com";
    
 const userLoginApi = "login";
 const userSignupApi = "signup";
    
 // Shared Preference keys 
 const kDeviceName = "device_name";
 const kDeviceUDID = "device_id";

 // Asset Constants
 const navBarLogoImage = "assets/images/home_images/sample.png
   

then import constants.dart file in required class and use it directly.

MaheshPeri19
  • 362
  • 6
  • 12
7

That's completely up to you.
Using static has no disadvantages.
Actually const is required for fields in a class.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • But doesn't using 'static const' keyword lead to the memory issue? how come? – TGLEE Aug 10 '20 at 09:50
  • 2
    Why do you think that? The difference is that const makes it part of the data section of the executable and non-const makes code that can create an instance part of the code section (when compiled to native code). That would require more memory for non-const after instances are created. Dart also canonicalizes const values. If you invoke a const constructor multiple times with the same parameter values, spread over your apps code, it will return the same instance every time. – Günter Zöchbauer Aug 10 '20 at 14:07
  • I'm just concerned that using too many static const variables might take up too much space in the heap memory because it's static after all. – TGLEE Aug 12 '20 at 07:57
  • 2
    The code instructions to create the objects at runtime won't take less space. As long as you don't add large BLOBS, this won't be an issue and you can't create consts in a for loop either. If you need to add every const individually and manually you'll have a hard time making this show up in memory usage. – Günter Zöchbauer Aug 12 '20 at 08:04
5

The best solution is to create an external file in which you will create a class and then add all your constants there.

An example:

In constant.dart, You will create the constant class

 import 'package:flutter/material.dart';
     class Constant {
      static Color myColor = Colors.blue;
      static Icon myIcon = Icon(Icons.search , color: Colors.red,);
      static TextStyle myStyle = TextStyle(
        fontSize: 17, 
        fontWeight: FontWeight.bold ,
        color: Colors.green);
    }

I had to import material.dart into the constant.dart file because I created Widget type constants. The widgets are contained in material.dart . If it's only about dart objects such as int , String etc . I won't need it.

enter image description here

Usage:

Column(
      children: [
          Text('Hello World' ,style: Constant.myStyle,),
          IconButton(icon: Constant.myIcon, onPressed: (){} ),
          Divider(color: Constant.myColor,)
                ],
              ),

Output :

enter image description here

Don't forget to import the library of your file which contains the constants, in my case here, it will be constant.dart.

Kab Agouda
  • 6,309
  • 38
  • 32
3

I like to organise my "constants" this way. It's easier for me to stay organised and to keep track what's already there. I can than do stuff like this: Tables.questions.id and Tables.anwerOptions.orderIndex

class Tables {
  static QuestionsTable get questions => QuestionsTable();
  static AnswerOptionsTable get answerOptions => AnswerOptionsTable();
}

class QuestionsTable {
  String get id => "id";
  String get title => "question";
  String get subtitle => "description";
  String get inputFieldType => "answer_input_type";
  String get answer => "answer";
}

class AnswerOptionsTable {
  String get id => "id";
  String get questionId => "question_id";
  String get answerOption => "answer_option";
  String get orderIndex => "order_index";
}
orotype
  • 449
  • 4
  • 8
  • But with that approach, they won't be constants and won't get the benefits of constants, causing it to use more memory and to have to make a few more steps to get it in each build. – Hyung Tae Carapeto Figur Jun 19 '21 at 22:00
  • What you suggest here _are not constants_! The benefit of constant they are allocated on compile time. But you approach will allocate memory on each "constant" access. – BambinoUA May 11 '22 at 06:51
3

Make a new dart file named constants.dart, and add the following code:

This way provide to you constants values with (context) or without (context):

=> With context:

import 'package:flutter/material.dart';

Color backgroundColor(context) {
  return Theme.of(context).backgroundColor;
}

or

=> Without context:

static Color colorB = Colors.blue;

enter image description here

=> Usage:

  Container(
    color: backgroundColor(context),
    child: Text('With context'),
  ),


  //or


  Container(
    color: colorB,
    child: Text('With context'),
  ),

enter image description here

rvndsngwn
  • 417
  • 2
  • 5
  • 11
0

Dart documentation says explicitly "AVOID defining a class that contains only static members." dart.dev/guides/language/effective-dart/design

The approach I use is creating one or more files to store those constants. Sometimes, when your project is too big it might have a lot of them, and in order to load less data, I prefer to separate them by the different contexts I would use them creating separate files. So I only import the ones that I would use.

  • 1
    And just below that, [the documentation](https://dart.dev/guides/language/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members) says explicitly _"However, this isn’t a hard rule. With constants and enum-like types, it may be natural to group them in a class."_. – Magnus Aug 24 '21 at 13:01
  • @Magnus Yes, but you can see the example they put there, it is an enum-like type. It is easier to organize like that, and you will not instantiate it. instead, you will only call *MyClass.myConstant*. But when you make it like a widget, then you will use unnecessary space in memory, not getting the benefits of the constants. – Hyung Tae Carapeto Figur Aug 24 '21 at 18:12
  • I'm not sure what you mean, I didn't say anything about widgets? The question is specifically asking about how to store constants, and using a class with static constants - as your example `MyClass.myConstant` - would be a perfectly good way to do it. – Magnus Aug 24 '21 at 19:35
  • @Magnus Sorry for not being specific in my answer, that I'm referring to the accepted answer approach. I just wanted to diverge from the accepted answer here. And the most voted answer is about putting everything together in a single file, and I'm just saying that it is more organized if you put in separated files for big projects. But of course, you can use the MyClass.myConstant when it becomes more organized in an enum-like syntax, specially if you can do it in a way it wont become one more distraction in the code, in order to keep readability. – Hyung Tae Carapeto Figur Aug 25 '21 at 17:47
0

i personally like this package flutter_gen 4.1.5 to add constant not only limited to string, this package also help you colors, assets, fonts etc (In short you can handle all const)

The Flutter code generator for your assets, fonts, colors, — Get rid of all String-based APIs.

Here is the example flutter_gen/example

Tushar Nikam
  • 1,445
  • 1
  • 14
  • 21
-1

Note dart language support defining constant outside of the class, so as many suggest creating a separate file for constants and importing it work well with respect to single coder working on a project.

Considering multiple coder working on the same project it's good practice to isolate the constant declaration inside a class is a good practice for a language that support object oriented programming

Raj
  • 1,156
  • 11
  • 15