Open In App

Singleton Class in Android

Last Updated : 05 Jul, 2025
Comments
Improve
Suggest changes
6 Likes
Like
Report

The Singleton Pattern is a software design pattern that restricts the instantiation of a class to just "one" instance. It is used in Android Applications when an item needs to be created just once and used across the board. The main reason for this is that repeatedly creating these objects, uses up system resources. The identical object should therefore only be created once and used repeatedly. It is utilized in situations where we only require a single instance of the class, such as with network services, databases, etc.

We, therefore, create a singleton class to implement the Singleton pattern in our project or product. In this article, we'll look at how to create singleton classes in Java and Kotlin.

Advantages of the Singleton Pattern

Many objects in a normal Android app only require a single global instance, whether they are used directly or are simply passed to another class. Examples include caches, the repository class, Retrofit, Gson, OkHttpClient, HttpLoggingInterceptor, and SharedPreferences. If we were to instantiate more than one of these kinds of objects, we would encounter issues like inaccurate app behavior, resource usage, and other unexpected outcomes.

Properties of Singleton Class

The characteristics of a typical singleton class are listed below:

  • Only one instance: Object created once and reused throughout the app
  • Globally accessible: Accessed via a static method or object
  • Private constructor: Prevents external instantiation
  • Thread-safe: Handles multithreading environments safely

Rules for Making a Class Singleton

To create a Singleton class, the guidelines listed below must be adhered to:

  • Private constructor
  • Static or companion reference to the instance
  • Thread-safe method to retrieve the instance
  • Instance should be lazily initialized (created when first needed)

Example: Singleton with Multi-Thread Lazy Initialisation -

Java
public class NetworkManager {

    private static volatile NetworkManager instance;

    private NetworkManager() {
        // private constructor
    }

    public static NetworkManager getInstance() {
        if (instance == null) {
            synchronized (NetworkManager.class) {
                if (instance == null) {
                    instance = new NetworkManager();
                }
            }
        }
        return instance;
    }

    public void makeNetworkCall() {
        // logic code here
    }
}
Kotlin
class NetworkManager private constructor() {

    companion object {
        @Volatile
        private var INSTANCE: NetworkManager? = null

        fun getInstance(): NetworkManager {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: NetworkManager().also { INSTANCE = it }
            }
        }
    }

    fun makeNetworkCall() {
        // logic code here
    }
}

Which is a class that can only have one instance at any given time. The getInstance() function is used to retrieve the singleton instance and creates it if it doesn't already exist. The function uses the synchronized block to ensure that only one thread can execute the creation of the instance at a time, preventing any race conditions that could occur if multiple threads try to create the instance simultaneously. The @Volatile annotation is used to make sure that the singleton instance is created only once and is visible to all threads.

The volatile keyword makes this singleton instance thread-safe with a private constructor, and we are performing two checks of "is equal to null" in the getInstance method. For instance, if we have two threads A and B, only one of them will be able to enter the synchronized block and both of them will observe that the instance is null at the synchronized keyword. Now, A enters while B waits, and when A notices the instance is null, A will create a new instance and leave the block. When thread B enters, it will notice that the instance is not null and then have the instance created by threat A itself.

Conclusion

The Singleton pattern is powerful but easy to misuse. It ensures a single instance, minimizes resource usage, and enables centralized control, but overuse or improper implementation can lead to poor app design and memory issues. The proper way would be:

  • Prefer object in Kotlin for singletons
  • Avoid holding Activity/Context references
  • Use Hilt/Dagger when possible for cleaner architecture

Article Tags :

Explore