Home > Software design >  Best practices for globals in flutter
Best practices for globals in flutter

Time:07-10

I'm building an app that has text to speech. It's possible to change the voice and set speed and such. I'm using a standard TTS from the public dev.

My question is, how to initialize this and use it throughout the app without passing recreating it everywhere since the object rarely will change.

Once it is set up, I just want to have it speak.

It's certainly not impossible to recreate it every time I need it.

I'm looking for best practices.

CodePudding user response:

Just have a class that holds all the information with an initialize method:

class Constants {

  static bool firstVar;
  static String secondVar;

  static void initialize() {
    firstVar = true;
    secondVar = "";
  }
}

// then call it in your main method before building the first widget

Constants.initialize();

CodePudding user response:

In this case, you need to use a state management architecture.

There are a good number of them to choose from. There are many articles and videos that explain how to use them. One thing they have in common is just what you're looking for. The ability to provide state at an app-wide level without reconfiguring in each widget.

Check out the Flutter Documentation here. Follow through the next pages and you'll have a good general overview of state management. Available options include, Provider, Riverpod, Redux, InheritedWidget, Stacked, etc. (Many of them actually).

For example, with Provider, you initialise the TTS in some TTS StateProvider (just an example). Then after wrapping your topmost MaterialApp in a ProviderScope, you can easily use the TTS in any widget as follows:

final tts = Provider.of<TTSProvider>(context).tts;
tts.doWhateverYouWant();

Another advantage of these architectures is that a good number of them permit good separation of concerns and dependency injection (or inversion of control).

In simpler terms, separation of concerns give you have the ability to write UI specific code separate from logic specific code. This way, if you want to debug, or change the packages or APIs you're using, you'll do them easily from one place (without fear of damaging the codebase). Besides it promotes clean code too.

Dependency Injection involves the use of services or something similar to obtain what widgets need to work without the widgets configuring the services themselves.

As you explore, you'll also notice that some architectures like Stacked permit you to manage app-wide state without the BuildContext. For another example for TTS, with Stacked Architecture, you could have:

final tts = locator<TTSService>().tts;
tts.doWhateverYouWant();

This pattern is useful because, in StatelessWidgets, the BuildContext is available only within the build method and you might need to use stuff outside it. In addition to obtaining the TTS anywhere in the Flutter code, you could do other things like BottomSheet, Navigation, Toast, etc. without BuildContext.

Furthermore, you'll notice that you will tend to use more StatelessWidgets as widgets no longer keep state for you.

On a final note, don't worry about performance. Flutter in itself is efficient and handles everything properly.

  • Related