How to create a Singleton class in Kotlin?

In Software Engineering, for tasks which are required to be performed only once, we use the Singleton Pattern. Singleton Pattern is a software design pattern that restricts the instantiation of the class to only “one” instance. So, to implement the Singleton pattern in our project or software, we make singleton class. So, in this blog, we will learn how to make a singleton class in Kotlin? So, let’s get started.

Singleton Class

A singleton class is a class that is defined in such a way that only one instance of the class can be created and is used where we need only one instance of the class like in logging, database connections, thread pool, etc.

Let’s take the example of a database connection. While dealing with databases, we need to connect to that particular database and after having the database transactions, we need to disconnect the database. So, the connection to database should be done only once and to achieve this, we need to make the instance of the class only once because if more than once instances are created then the same database will be connected by more than one thread and this will result in data inconsistency.

Properties of Singleton Class

Following are the properties of a typical singleton class:

  1. Only one instance: The singleton class has only one instance and this is done by providing an instance of the class, within the class. Also, outer classes and subclasses should be prevented to create the instance.
  2. Globally accessible: The instance of the singleton class should be globally accessible so that each class can use it.

Rules for making a class Singleton

Following are the rules that should be followed to make a class singleton:

  1. A private constructor
  2. A static reference of its class
  3. One static method
  4. Globally accessible object reference
  5. Consistency across multiple threads

Singleton Example

Following is the example of Singleton class in java:

public class Singleton {

    private static Singleton instance = null;

    private Singleton(){
    }

    private synchronized static void createInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
    }

    public static Singleton getInstance() {
        if (instance == null) createInstance();
        return instance;
    }

}

When creating the instance to ensure that there is no thread interference, we use the synchronized keyword.

Let’s look at the Kotlin code for the same. Below is the Kotlin code for Singleton class:

object Singleton

Ok, what to do after this?

Nothing! Are you kidding? No, that’s the code for using Singleton class in Kotlin. Very simple? Don’t worry, let’s look at the explanation.

In Kotlin, we need to use the object keyword to use Singleton class. The object class can have functions, properties, and the init method. The constructor method is not allowed in an object so we can use the init method if some initialization is required and the object can be defined inside a class. The object gets instantiated when it is used for the first time.

Let’s have an example of the Singleton class in Kotlin.

object Singleton{
    
    init {
        println("Singleton class invoked.")
    }
    var variableName = "I am Var"
    fun printVarName(){
        println(variableName)
    }

}

fun main(args: Array<String>) {     
    Singleton.printVarName()
    Singleton.variableName = "New Name"
        
    var a = A()
}

class A {

    init {
        println("Class init method. Singleton variableName property : ${Singleton.variableName}")
        Singleton.printVarName()
    }
}

Here, in the above example, we are having one function named printVarName() and one property named “variableName”. When A class is instantiated, then changes can be reflected to the object class. So, the output of the above code will be:

Singleton class invoked.
I am Var
Class init method. Singleton variableName property : New Name
New Name

Object extending a class

You can use an object in Kotlin to extend some class or implement some interface just like a normal class. Let’s have an example of the same:

fun main(args: Array<String>) {
    var a = A()
        Singleton.printVarName()
    }

open class A {

    open fun printVarName() {
        print("I am in class printVarName")
    }

    init {
        println("I am in init of A")
    }
}

object Singleton : A() {

    init {
        println("Singleton class invoked.")
    }

    var variableName = "I am Var"
    override fun printVarName() {
        println(variableName)
    }
}

And the output of the above code will be:

I am in init of A
I am in init of A
Singleton class invoked.
I am var

So, you can use object class just like a normal class in most of the cases.

Singleton class with Argument in Kotlin

In the earlier part of the blog, we learned that we can’t have constructors in a singleton class. To initialize something, we can do so by using init in the singleton class. But what if you need to pass some argument for initialization just like in parameterized constructors. Since we can’t use constructors here. So, we need to find some other way of doing the same.

If we are passing some argument, then the singleton class must be aware of the same. A situation may arise when the singleton class is generated by any external tool or library such as Retrofit and the instance of the class is retrieved using some factory method. So, here your singleton class can’t be an object and you need to declare it as an interface or abstract class.

If we particularly talk about Android, we know that in Android we generally need to pass a context instance to init block of a singleton. This can be done using Early initialization and Lazy initialization. In early initialization, all the components are initialized in the Application.onCreate() using the init() functions. But this results in slowing down the application startup by blocking the main thread. So, it is generally advised to use the lazy initialization way. In lazy initialization, we use the context as an argument to a function returning the instance of the singleton. We can achieve this by using a SingletonHolder class. Also, to make it thread-safe, we need to implement a synchronized algorithm and a double-checked locking algorithm like below:

open class SingletonHolder<out T: Any, in A>(creator: (A) -> T) {
    private var creator: ((A) -> T)? = creator
    @Volatile private var instance: T? = null

    fun getInstance(arg: A): T {
        val checkInstance = instance
        if (checkInstance != null) {
            return checkInstance
        }

        return synchronized(this) {
            val checkInstanceAgain = instance
            if (checkInstanceAgain != null) {
                checkInstanceAgain
            } else {
                val created = creator!!(arg)
                instance = created
                creator = null
                created
            }
        }
    }
}

The above code is the most efficient code for double-checked locking system and the code is somehow similar to the lazy() function in Kotlin and that’s why it is called lazy initialization. So, whenever you want to singleton class with arguments then you can use the SingletonHolder class.

Here, in the above code, in place of the creator function which is passed an argument to the SingletonHolder, a custom lambda can also be declared inline or we can pass a reference to the private constructor of the singleton class. So, the code will be:

class YourManager private constructor(context: Context) {
    init {
        // Init using context argument
    }

    companion object : SingletonHolder<YourManager, Context>(::YourManager)
}

Now, the singleton can be easily invoked and initialized by writing the below code and this is lazy as well as thread-safe :)

YourManager.getInstance(context).doSomething()

That’s it for the Singleton blog. Hope you like this blog. You can also refer to the Kotlin website. To learn more about some of the cool topics of Android, you can visit our blogging website and can join our journey of learning.

Keep Learning :)

Team MindOrks!