Singletons in Android

Avoid them or at least think twice before use them

Michael Spitsin
11 min readJul 22, 2016

There are a lot of articles and posts about Singleton Pattern. In fact there are many articles about how bad Singleton Pattern can be and how especially it can be harmful in Android. Here a bunch of them, here, here, here, here and here.

But every post concerns only about some small specific problem. Some of them about memory leaking, some of them about loosing a state, some of them about multiprocessing. But I didn’t find an article, that covered all topics. And I will try to touch all of topics, or at least most of them, most of needed to understand, that Singletons are evil, and especial in Android (at least you need to choose them wisely and provide some mechanism to keep their states and e.t.c.).

Also I do my best to improve my knowledges and skills in programming, in Java, in Android. So I think this article will be useful not only for you, but for me, too.

So, what if I have simple Singleton

Let’s look at this code:

public class CarelessSingleton{
public static final CarelessSingleton instance = new CarelessSingleton();
private Object someState;

private CarelessSingleton() {}
public void setState(Object state) {
this.someState = state;
}
public Object getState() {
return someState;
}
}

Except ‘lazy initialisation’ and ‘multithreading’ this code has two main problems:

  1. We have published state of singleton that can be changed everywhere. It’s not an Android problem, it’s an architectural problem. Of course we can say: “We know, where to set value”, “There are only couple places and e.t.c”. But still the fact is that such Singleton provides a global variable. And moreover you can not create second or third instance. There is only one instance.
  2. For android there is more dangerous problem with stateful mutable Singleton. Losing state. If your singleton provides some state that can be changed in your application, then you can easily losing state.

Let’s provide some simple application that uses our Singleton. Here layout for activity:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="@+id/test_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="0"
/>
<Button
android:id="@+id/test_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="16dp"
android:text="Set global 5"
/>
</FrameLayout>

And activity:

public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = (TextView) findViewById(R.id.test_text);
displayState();
findViewById(R.id.test_button)
.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view) {
CarelessSingleton.instance.setState(5);
displayState();
}
});
}
private void displayState() {
Object state = CarelessSingleton.instance.getState();
textView.setText(String.valueOf(state));
}
}

Yeap, that’s all. Now we can run our application. And we will see 0 in center of screen. Then we click on the button and see 5 in center. We can rotate an application, for example, or press Home button and then on application icon. And everything will be normal. We will still have 5 on center of the screen. But if we run bunch of other apps: play some games, write couple of emails and e.t.c, and then go back to our application we will se 0 instead of 5. What? What happened?

Problem

During our usage of phone, system was needed more memory and it saw that our application was not used for a while. So it killed it. And then when we went back to our app, system recreated it, restoring some state. Of course our singleton was not saved and restored, because it’s naive and didn’t know that can be killed.

Solution

There is no so obvious solution as it seems, because such simple singleton can be changed everywhere. In every Activity, in every Fragment, in services — everywhere within its process. Of course, all that we know exactly is that we need to provide some saving mechanism. There are two fast solutions that can come to mind, but both of them are not perfect. In defense, I would say, that using such singleton is not perfect solution of some architect problem.

First variant. We can create saveState(Bundle outState)/restoreState(Bundle state) similarly to onSaveInstanceState(Bundle outState)/onRestoreInstanceState(Bundle outState) for our Singleton and then call them wherever we want.

public void saveState(Bundle state) {
state.putInt(SINGLETON_STATE, getState());
}
public void restoreState(Bundle state) {
setState(state.getInt(SINGLETON_STATE));
}

But this approach has huge flaw. You need to decide where to save state. In fact, you can choose only between activities, views and fragments. For example, if you changed state of Singleton in activity, then close it, but you have background service that changed state one more time, then app was killed and restarted by the system, you will lose last updating, that was made by service. And of course most likely you will have to call these functions (saveState, restoreState) from all Activities, Views and Fragments which somehow (directly or not) affects to state of Singleton, which produces a lot of boilerplate code.

Small improvement of this solution: provide not bundle but anything that might store state of your Singleton. For example, it might be SharedPreferences, Stream or maybe your own Class/Interface. Moreover, you can make those methods parameterless, so your Singleton will be implement it’s own saving mechanism. Thus, you will able to call save/restore methods from everywhere, but as I said it can turn out a huge boilerplate, if your singleton managed from many places.

Second variant. Singleton can provide its own saving mechanism and call ‘save’ methods inside setState, giving to us a possibility of “auto” saving. Also in Singleton’s initialization ‘restore’ method will be called, giving to us “auto” restoring mechanism.

Unlike previous variant, this one frees us from writing a lot of extra code. But it have shortcoming of permanent saving any setting state. For example, if you will have loop that iteratively sets new state, then every time save mechanism will be invoked. And it can be harmful for performance.

You can combine these two variant, giving to client opportunity to disable auto save when it will frequently sets new states and enable it later.

What have we learned

Above example shows that naive stateful mutable singleton can be a mess, if you not handle it properly. You need to always think, when you actually need to change it state to avoid many “entry points”. If you care about state of singleton, you need always think, where you need to save it and how.

My Singleton stores Context

Let’s look at the code:

public class ContextSingleton {
private static ContextSingleton instance;

public static void init(Context context) {
if (instance == null) {
instance = new ContextSingleton(context);
}
}

public static ContextSingleton getInstance() {
return instance;
}

private final Context context;

private ContextSingleton(Context context) {
this.context = context;
}

public Context getContext() {
return context;
}
}

“So what’s the problem in this code?” you will say, “this singleton has immutable instance, there is no problems with state and e.t.c, what is wrong with you man?”

Let’s omit problems with multithreading. We initializing our singleton in launch activity, for example through ContextSingleton.init(this), then work with our activity, then go to second activity, third, fourth and get’s OutOfMemoryException. What’s wrong?

Problem

In Android there are class called Context. It’s required, when you need to get access to services, resources or internal files in your application. It is used for creating views and launching another Activities. So it might seem that Context would be very helpful in your singleton object, because you can do a lot of stuff with it and thus encapsulate many things in your singleton.

But it is an illusion. Of course there are a lot of libraries that provides singletons or single instances that keeps Context reference, but it is application context, not some ‘local’ context.

Yes, there are Application context and, for example, Activity context. They both are instances of Context class, but first attached to application lifecycle and second to activity lifecycle. First will be destroyed, when app will be killed, second, when activity will be killed.

Now, as we remember our singleton lives all across application. So it will be destroyed when application will be destroyed. Thus when we pass, for example, activity context in singleton and then run another activity and then kill application, then everything will be all right, but if second activity will require a lot of memory, for example, then system will decide to kill first activity, but it will fail, since there are reference to it in our singleton, and we receive OutOfMemoryExeption. It is unpleasant to be honest.

Solution

In short. Do not pass any context except app context in your singleton. Please. For more sequrity change initialization code little bit:

public static void init(Context context) {
if (instance == null) {
context = context.getApplicationContext();
instance = new ContextSingleton(context);
}
}

In details. You can pass activity context if you want, but you need to be aware all the time, you need to clear reference when you stop working with your activity, replace it with another reference, when you start new activity. So it can be huge headache. I highly recommend to not pass any context in your singleton, but, if you still want to do it, please, pass only application context. And if you are 100% sure that you need to pass some ‘local’ context in your singleton (for example, you need to create an mechanism of processing bitmaps in background and displaying them in attached views), think about ‘release context reference’ mechanism. For example, you can use WeakPreference of your context objects, so system will be able to destroy them, during garbage collecting.

What have we learned

Think twice if you want to store context in your singleton. You need to be sure that using the context will be justified. And if you will use some ‘local’ context, provide mechanism for releasing its reference to allow garbage collector mark this object as unused and collect it, otherwise you might face with memory leaks in your app.

I want to use my singleton in Activity and Remote Service

Then I have bad news for you. You can not do it. The reason is simple: your activities, fragments and other ui components are placed in application process and your Remote Service placed in remote process. And those processes are different. And there is only one way you can interact with them. It’s AIDL.

If, for example, for activities and local services you can make global static state and share it between them (which is bad, but also what singleton often actually does), then for activity and remote service you can not do such thing, because each process has own class loader.

Actually in our case we will have two instances of singleton. One in process of application and one in remote process.

Solution

If you want to use singleton that share some state through processes then, please, remove this singleton. Consider to use AIDL, broadcasts, intents. Remember, there are no singletons in multiprocessing app, only in single process. So if you have, for example, remote process and singleton in your app, make sure that this singleton be used only in one of the processes.

I have immutable singleton

As for me Immutable Singletons (with some restrictions) are one of the options to build proper single instances in android, because you know that your instance sets up only once, during creation phase and then not changing. So it’s more easily to keep it around, even through app restarting.

Although, it could be good solution of some problem, it can be a mess, if you for example create Immutable Singleton passing local context to it and not provide any mechanism to release it, as I said earlier.

One of good usings of Immutable Singletons is to use so-called ‘extension’ of Singleton named Enumeration. Enums have some restrict, predefined number of instances, as for Singleton. But unlike Singleton there can be 2, 3, 10 instances of some class. One of good examples of enums, is to use them as typed constants. For example:

public static final String CONST_1 = “const 1”;
public static final String CONST_2 = “const 2”;
public static final String CONST_3 = “const 3”;

Instead of defining string constants like that, we can define them like this:

public enum CONSTANTS {
CONST_1, CONST_2, CONST_3
}

This approach will give you typed constants and, thus, prevent you from checking their validity in places where you will use them.

Problem

Actually there is no such big performance or memory problem. But there is an architectural problem. If you have in application immutable singleton then you need to think do you actually need it.

Solution

There are three types of immutable singletons that could came to mind right now:

  1. Singletons without state but with pack of functions. So you have singleton that have only functionality, but not state. So in code you have something like ‘Something.INSTANCE.computeSomething(SomethingOther other)’. In this case, first, you need to think about replacing singleton with ‘Utility’ class. It’s a class with private empty constructor and only static methods. So invocation will be look like ‘SomeUtil.computeSomething(SomethingOther other)’, which reduce redundant INSTANCE word. Second, if SomethingOther class is not library class, but your class, consider to move ‘computeSomething’ method to it, so invocation will be look like: ‘other.computeSomething()’.
  2. Singletons with initial state (not context) and pack of functions. As for previous point you need to provide Utility class with initial state in private constructor and static methods.
  3. Singletons with application context state and pack of functions. These singletons often appears from libraries, which are want to interact with app somehow. If you want to use something similar in your application. Consider to create not singleton, but class with constructor that has application context as parameter and invoke it in application’s onCreate callback, then store it in static field of Application class and provide static getter for accessing to it.

Third point leads us to the next section.

How we can create proper Singletons

The answer permeates the entire article. Don’t use singletons.

  1. They provide global state, which is not OOP solution
  2. They can lose their state
  3. They can leak your context
  4. They hard to test (you alway need to clear or restore init state for stateful singletons)
  5. They are not actually singletons in multiprocessing apps
  6. They can be executed everywhere and it can lead to reducing maintainability
  7. In multithreading apps they can change state from any thread and this can lead to unexpected results
  8. They can not be extended

For now I don’t use singletons. If I need to provide a global state I create a single instance of some class, and single instance concept differs from singleton. Single instance is created to provide some global state (which is bad in OOP generally, but is normal in android), but you can still create multiple instances of your class. This gives us possibility to properly test our class, or create local instances for doing some small specific work, or to extend them with new logic.

So to create global instance of our class we need to extend application class and add initialisation of our class in onCreate method. Then we need to provide static getter for our global instance.

public class MyApplication extends Application {
private static Something something;

public void onCreate() {
super.onCreate();
something = new Something();/new Something(getApplicationContext())/new Something(InitState state);
}

public static Something getSomething() {
return something.
}

}

Then we can invoke anywhere in code ‘getSomething()’ and work with our global instance.

Afterwords

Singletons are bad and you should avoid them. Especially in Android. But if you really need global state, write your class properly and create global instances through application creation phase.

P.S.: Links

If you liked article there are other by me about improve working with permissions, saving states and refactoring base fragment.

--

--

Michael Spitsin

Love being creative to solve some problems with an simple and elegant ways