78

I have followed this link and successfully made singleton class in Android. http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/

Problem is that i want a single object. like i have Activity A and Activity B. In Activity A I access the object from Singleton class. I use the object and made some changes to it.

When I move to Activity B and access the object from Singleton Class it gave me the initialized object and does not keep the changes which i have made in Activity A. Is there any other way to save the changing? Please help me Experts. This is MainActivity

public class MainActivity extends Activity {
    protected MyApplication app;        
    private OnClickListener btn2=new OnClickListener() {    
        @Override
        public void onClick(View arg0) {
            Intent intent=new Intent(MainActivity.this,NextActivity.class);
            startActivity(intent);              
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Get the application instance
        app = (MyApplication)getApplication();

        // Call a custom application method
        app.customAppMethod();

        // Call a custom method in MySingleton
        Singleton.getInstance().customSingletonMethod();

        Singleton.getInstance();
        // Read the value of a variable in MySingleton
        String singletonVar = Singleton.customVar;

        Log.d("Test",singletonVar);
        singletonVar="World";
        Log.d("Test",singletonVar);

        Button btn=(Button)findViewById(R.id.button1);
        btn.setOnClickListener(btn2);
    }

}

This is NextActivity

public class NextActivity extends Activity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_next);

            String singletonVar = Singleton.customVar;

            Log.d("Test",singletonVar);
        }
  }

Singleton Class

public class Singleton
{
    private static Singleton instance;

    public static String customVar="Hello";

    public static void initInstance()
    {
    if (instance == null)
    {
      // Create the instance
      instance = new Singleton();
    }
    }

    public static Singleton getInstance()
    {
     // Return the instance
     return instance;
     }

     private Singleton()
     {
     // Constructor hidden because this is a singleton
     }

     public void customSingletonMethod()
     {
     // Custom method
     }
 }

and MyApplication

public class MyApplication extends Application
    {
    @Override
    public void onCreate()
    {
    super.onCreate();

     // Initialize the singletons so their instances
     // are bound to the application process.
     initSingletons();
     }

     protected void initSingletons()
     {
     // Initialize the instance of MySingleton
     Singleton.initInstance();
     }

     public void customAppMethod()
     {
     // Custom application method
    }
}

When i run this code, i get Hello which i have initialized in Singleton then World which i gave it in MainActivity and again shows Hello in NextActivity in logcat. I want it to show world again in NextActivity. Please help me to correct this.

Android
  • 1,420
  • 4
  • 13
  • 23
user2216292
  • 799
  • 1
  • 5
  • 6
  • In MainActivity - why are you calling Singleton.getInstance() twice? – IgorGanapolsky Sep 19 '14 at 14:39
  • 1
    This mainly happened because when you call String singletonVar = Singleton.customVar; in java this assignment operation doesn't assign reference to Singleton.customVar in memory it simply create new variable called singletonVar and so when you change SingltonVar you simply changing the value of the local variable not the singleton variable. – M_AWADI Oct 08 '15 at 08:50
  • Old, but, String singletonVar = Singleton.customVar; String is a primitive type so it is not an object, you are simply copyng the currect value from the singleton to the loca variable, then you modify the value of the local variable – Pecana May 12 '18 at 13:33
  • The link is wrong – Slaknation Dec 22 '18 at 20:48

8 Answers8

61

Tip: To create singleton class In Android Studio, right click in your project and open menu:

New -> Java Class -> Choose Singleton from dropdown menu

enter image description here

Lazy
  • 1,807
  • 4
  • 29
  • 49
48

EDIT :

The implementation of a Singleton in Android is not "safe" (see here) and you should use a library dedicated to this kind of pattern like Dagger or other DI library to manage the lifecycle and the injection.


Could you post an example from your code ?

Take a look at this gist : https://gist.github.com/Akayh/5566992

it works but it was done very quickly :

MyActivity : set the singleton for the first time + initialize mString attribute ("Hello") in private constructor and show the value ("Hello")

Set new value to mString : "Singleton"

Launch activityB and show the mString value. "Singleton" appears...

Akayh
  • 718
  • 6
  • 8
  • It's an example code of singleton between activity. If you need more help post your code (or a simple example) to see the problem – Akayh May 13 '13 at 12:46
  • 3
    It's just because the string is copied in singletonVar and not a reference to it. If you change directly the static variable as follow : Singleton.customVar="World"; it's work. – Akayh May 13 '13 at 14:43
  • 6
    Just a heads up, this is *NOT* thread safe! Always, remember Murphy's Law. One way to make it thread safe is to use the `synchronized` keyworkd in your `getInstance()` method. – dazito Jun 17 '14 at 08:40
  • @dwnz synchronized keyword has a performance penalty. Why use it if it's not a multi-threaded environment? – IgorGanapolsky Sep 19 '14 at 14:42
  • @IgorGanapolsky `synchronized`, as I said, is one of the possible ways to do. Ofc there are other ways, probably `synchronized` is the simplest way. Regarding your question, you can create threads with Android and run them with concurrency. – dazito Sep 30 '14 at 23:48
  • @ Akayh it is not going to be work assume in activity A you set some value in string and goes to activity b and on activity suppose app goes in background then on low memory cases android system terminate our process and ...unfortunately we will get nullpointer exception..i faced this situation i m also looking for answer http://stackoverflow.com/questions/39115735/singleton-class-that-survives-process-termination?noredirect=1#comment65579635_39115735 – Hardik Mehta Sep 12 '16 at 09:34
  • how to achieve from recyclerview list and detailview two differennt activities in recyclerlist if user do any changes for list item for status changes and after notifydatasetchanged and then click for detailview that object is passed through extras.in detailview if user do revoke that status changes how to get back and reflect on list please help me – Harsha Oct 29 '16 at 05:56
  • 4
    @Akayh Could you please explain why Singleton it is not safe on Android? Is it safe only not safe on Activities or its not safe on Application as well? – Saba Dec 26 '17 at 23:01
  • 1
    "Singleton in Android is not safe" - needs a reference and ideally an explanation. – noelicus Aug 02 '18 at 06:25
37

It is simple, as a java, Android also supporting singleton. -

Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns.

-> Static member : This contains the instance of the singleton class.

-> Private constructor : This will prevent anybody else to instantiate the Singleton class.

-> Static public method : This provides the global point of access to the Singleton object and returns the instance to the client calling class.

  1. create private instance
  2. create private constructor
  3. use getInstance() of Singleton class

    public class Logger{
    private static Logger   objLogger;
    private Logger(){
    
            //ToDo here
    
    }
    public static Logger getInstance()
    {
        if (objLogger == null)
       {
          objLogger = new Logger();
       }
       return objLogger;
       }
    
    }
    

while use singleton -

Logger.getInstance();
Rakesh
  • 2,732
  • 29
  • 28
21

answer suggested by rakesh is great but still with some discription Singleton in Android is the same as Singleton in Java: The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:

1) Ensure that only one instance of a class is created

2) Provide a global point of access to the object

3) Allow multiple instances in the future without affecting a singleton class's clients

A basic Singleton class example:

public class MySingleton
{
    private static MySingleton _instance;

    private MySingleton()
    {

    }

    public static MySingleton getInstance()
    {
        if (_instance == null)
        {
            _instance = new MySingleton();
        }
        return _instance;
    }
}
ashish.n
  • 1,234
  • 14
  • 30
  • 1
    Definitely this is the best approach because It made a lazy constructor, in other words, It is only instantiated when `getInstance()` is called at first time. – Ângelo Polotto Nov 23 '18 at 10:56
17

As @Lazy stated in this answer, you can create a singleton from a template in Android Studio. It is worth noting that there is no need to check if the instance is null because the static ourInstance variable is initialized first. As a result, the singleton class implementation created by Android Studio is as simple as following code:

public class MySingleton {
    private static MySingleton ourInstance = new MySingleton();

    public static MySingleton getInstance() {
        return ourInstance;
    }

    private MySingleton() {
    }
}
Community
  • 1
  • 1
Adam
  • 26,549
  • 8
  • 62
  • 79
  • 1
    This is the simplest and the fastest solution. If you call getInstance() a lot in a loop then the other answers with a check for null will be significantly slower. – BitByteDog Dec 10 '16 at 22:29
6

You are copying singleton's customVar into a singletonVar variable and changing that variable does not affect the original value in singleton.

// This does not update singleton variable
// It just assigns value of your local variable
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);

// This actually assigns value of variable in singleton
Singleton.customVar = singletonVar;
Dusan
  • 5,000
  • 6
  • 41
  • 58
3

I put my version of Singleton below:

public class SingletonDemo {
    private static SingletonDemo instance = null;
    private static Context context;

    /**
     * To initialize the class. It must be called before call the method getInstance()
     * @param ctx The Context used

     */
    public static void initialize(Context ctx) {
     context = ctx;
    }

    /**
     * Check if the class has been initialized
     * @return true  if the class has been initialized
     *         false Otherwise
     */
    public static boolean hasBeenInitialized() {
     return context != null;

    }

    /**
    * The private constructor. Here you can use the context to initialize your variables.
    */
    private SingletonDemo() {
        // Use context to initialize the variables.
    }

    /**
    * The main method used to get the instance
    */
    public static synchronized SingletonDemo getInstance() {
     if (context == null) {
      throw new IllegalArgumentException("Impossible to get the instance. This class must be initialized before");
     }

     if (instance == null) {
      instance = new SingletonDemo();
     }

     return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Clone is not allowed.");
    }
}

Note that the method initialize could be called in the main class(Splash) and the method getInstance could be called from other classes. This will fix the problem when the caller class requires the singleton but it does not have the context.

Finally the method hasBeenInitialized is uses to check if the class has been initialized. This will avoid that different instances have different contexts.

jiahao
  • 3,373
  • 2
  • 35
  • 36
  • Android Studio will treat this answer as an issue - memory leak - since you have a Context set within a static "instance" of another class. This pattern is now useless – narkis Aug 23 '16 at 01:16
  • @narkis Interesting. If this is true, then when the people has the static instance of Context inside the CustomApplication will also generate a memory leak. You should warm all us about it :-) – jiahao Aug 23 '16 at 13:59
2

The most clean and modern way to use singletons in Android is just to use the Dependency Injection framework called Dagger 2. Here you have an explanation of possible scopes you can use. Singleton is one of these scopes. Dependency Injection is not that easy but you shall invest a bit of your time to understand it. It also makes testing easier.

unlimited101
  • 3,653
  • 4
  • 22
  • 41