DevInTheMiddle_

Creating Singletons in Flutter with Dart

Published on Aug 03, 2020

Yes, I admit it - I put Flutter in the title just to get some more views, but hey...

It ain't much, but it's honest work source: knowyourmeme.com

Anyway, this is a pretty interesting topic! Dart syntactic sugar can look tricky at first sight, in this article we are going to unwind the skein of singletons.

A simple Class in Dart is usually declared as follows:

class Hello {
    Hello();
    void sayHello() { 
        print("Hello!"); 
    } 
}

In this case our Class will not accept any argument, having an empty constructor.

Dart automatically recognizes Class constructors, as they are functions with the same name of the parent Class, without any return type declaration - as constructors do not return values.

Writing Hello() is just syntactic sugar for Hello() {}.

Classes can have multiple constructors by making use of named constructors:

class Hello {
    String name = "nobody";
    Hello();
    Hello.named(String name) {
        this.name = name;
    }
    void sayHello() {
        print("Hello to ${name}!"); 
    }
}

In this case we can call either

hello = new Hello();
hello.sayHello(); // Hello to nobody

or

hello = new Hello.named('Jon');
hello.sayHello(); // Hello to Jon

Now, if putting an underscore in front of variables and methods make them private, we can do the same with named constructors!

class Hello {
    Hello._private();
    void sayHello() {
        print("Hello!");
    }
}

In this case Hello() _private constructor cannot be called publicly (creating new Hello() instance will return an Error: Method not found).

Are you thinking the same?

If a Singleton is a Class that may not be instantiated more than once, we can leverage the above property to create one!

class Hello {
    Hello._private();
    static final Hello _instance = Hello._private();
    static Hello get singleton {
        return _instance;
    }
    void sayHello() {
        print("Hello!");
    }
}

Given that _private is still accessible from the inside, we call the _private constructor by setting a private static variable _instance the first time the Class is loaded.

In order to access the Class instance from the outside, we need a public getter (in this case, singleton) that can be called from anywhere:

var hello = Hello.singleton;
hello.sayHello();

Anyway, this syntax is not as nice as calling new:

var hello = new Hello();
hello.sayHello();

To be able to use the above format - and still not getting a new instance of Hello() every time we call it - we need Dart Class factory:

class Hello {
    Hello._private();
    static final Hello _instance = Hello._private();
    static Hello get singleton {
        return _instance;
    }
    factory Hello() {
        return singleton;
    }
    void sayHello() {
        print("Hello");
    }
}

factory keyword allows to override the default constructor behavior, in this case we are returning the Class instance already in memory.

Here we go! A nice Singleton in Dart that can be used to save precious resources when a Class constructor is called.

Written by

Simone Manzi

GitHub

Senior Software Engineer with strong expertise in Web Development, now writing bugs as Data Engineer.
Thinks of himself to be a real Full-Stack... Only until his impostor syndrome does not take over!