377

Recalling this post enumerating several problems of using singletons and having seen several examples of Android applications using singleton pattern, I wonder if it's a good idea to use Singletons instead of single instances shared through global application state (subclassing android.os.Application and obtaining it through context.getApplication()).

What advantages/drawbacks would both mechanisms have?

To be honest, I expect the same answer in this post Singleton pattern with Web application, Not a good idea! but applied to Android. Am I correct? What's different in DalvikVM otherwise?

EDIT: I would like to have opinions on several aspects involved:

  • Synchronization
  • Reusability
  • Testing
Community
  • 1
  • 1
Martín Schonaker
  • 7,273
  • 4
  • 32
  • 55

10 Answers10

298

I very much disagree with Dianne Hackborn's response. We are bit by bit removing all singletons from our project in favor of lightweight, task scoped objects which can easiliy be re-created when you actually need them.

Singletons are a nightmare for testing and, if lazily initialized, will introduce "state indeterminism" with subtle side effects (which may suddenly surface when moving calls to getInstance() from one scope to another). Visibility has been mentioned as another problem, and since singletons imply "global" (= random) access to shared state, subtle bugs may arise when not properly synchronized in concurrent applications.

I consider it an anti-pattern, it's a bad object-oriented style that essentially amounts to maintaining global state.

To come back to your question:

Although the app context can be considered a singleton itself, it is framework-managed and has a well defined life-cycle, scope, and access path. Hence I believe that if you do need to manage app-global state, it should go here, nowhere else. For anything else, rethink if you really need a singleton object, or if it would also be possible to rewrite your singleton class to instead instantiate small, short-lived objects that perform the task at hand.

Prags
  • 2,457
  • 2
  • 21
  • 38
mxk
  • 43,056
  • 28
  • 105
  • 132
  • 1
    I tried to replace my singleton in favor of a Application class, and I have a couple of difficulties. For instance, a service Handler cannot access the Application. – rds May 30 '11 at 20:25
  • You can always reach the app instance through a context (`Context.getApplication[Context]`), so you could keep a reference somewhere in your `Handler`. Just be careful to not leak that reference. – mxk May 31 '11 at 07:57
  • 1
    can you please add some code in your answer? differentiating good-bad and making your point stronger. – xxxxxxxxxadfas Jul 29 '11 at 07:14
  • 132
    If you are recommending Application, you are recommending use of singletons. Honestly, there is no way around it. Application *is* a singleton, with crappier semantics. I won't get into religious arguments about singletons something you should never use. I prefer to be practical -- there are places where they are a good choice for maintaining per-process state and can simplify things by doing so, and you can just as well use them in the wrong situation and shoot yourself in the foot. – hackbod Aug 02 '11 at 01:50
  • 18
    True, and I did mention that the "app context can be considered a singleton itself". The difference is that with the app instance, shooting yourself in the foot is a lot harder, since its life-cycle is handled by the framework. DI frameworks like Guice, Hivemind, or Spring also make use of singletons, but that's an implementation detail the developer should not care about. I think it's generally safer to rely on framework semantics being correctly implemented rather than your own code. Yes, I admit I do! :-) – mxk Aug 02 '11 at 07:44
  • 96
    Honestly it does not prevent you from shooting yourself in the foot any more than a singleton does. It is a little confusing, but there is *no* lifecycle of Application. It is created when your app starts (before any of its components are instantiated) and its onCreate() called at that point, and... that is all. It sits there and lives forever, until the process is killed. Just like a singleton. :) – hackbod Aug 02 '11 at 19:19
  • 30
    Oh one thing that may be confusing this -- Android is very much designed around running apps in processes, and managing the lifecycle of those processes. So on Android singletons are a very natural way to take advantage of that process management -- if you want to cache something in your process until the platform needs to reclaim the process's memory for something else, putting that state in a singleton will do that. – hackbod Aug 02 '11 at 19:21
  • 7
    Okay fair enough. I can only say that I haven't looked back ever since we made the step away from self-managing singletons. We're now opting for a lightweight DI-style solution, where we do keep one factory singleton (RootFactory), which in turn is managed by the app instance (it's a delegate if you will). This singleton manages common dependencies all app components rely on, but instantiation is managed in one single location -- the app class. While with that approach one singleton remains, it is confined to the Application class, so no other code module know about that "detail". – mxk Aug 03 '11 at 16:43
  • 2
    These are classic criticisms of Singleton that I agree with in principle. In practice there are times when they make complete sense, as long as you've kept the dangers in mind -- and in fact these concerns are true for all objects: reduce mutable state, encapsulate access to the state you have to maintain, etc. I'd be interested to know what indeterminism you're referring to, Matthias. Are you using a thread-safe singleton pattern or just the classic "if (instance == null)", etc. pattern? Not questioning your practice -- I wanna know if I'm missing something. :) – Dave Sims Feb 28 '12 at 17:03
  • 6
    And, by the way, is OK if I agree with both Diane and Matthias? :) – Dave Sims Feb 28 '12 at 19:33
  • 3
    Hey Dave, what I was referring to is lazy initialization (which is often used along with Singletons, although certainly not necessary). There is nothing wrong with lazy initialization of course, but in conjunction with Singletons it implies "lazy global state" that pops into being the first time the Singleton is accessed. This can lead to subtle bugs where reordering of statements leads to different execution behavior. Personally I find that if a solution to a problem requires me to juggle with so many subtle issues, it's probably not a good solution. – mxk Mar 01 '12 at 10:23
  • OK, bottom line: any singleton you're ever going to create, AND the Application object are effectively subject to being purged at any time from the point of view of the app. The proper pattern is for each Activity etc. to check to see if the singleton has been lost in their onCreate(). This also implies that every object must save enough information in onSaveInstanceState() to re-create the singleton whenever required. Is that all correct? – Edward Falk Apr 10 '12 at 03:18
  • 1
    The Application object will never be purged as long as the application process is alive, and neither is any singleton object (or *any* object for that matter) that is reachable through a strong reference. The pros and cons mentioned here were mostly w.r.t. to access path (which has a strong impact on e.g. testability) and life-cycle, not life time. So, no, a singleton cannot be "lost", nor can the application object. – mxk Apr 10 '12 at 12:05
  • 1
    Yes, but the process can be killed at any time (as long as none of its activites are actually active), correct? – Edward Falk Apr 10 '12 at 18:38
  • 1
    That's correct, but in that case if the user would switch back to the app, Android would simply restart it (i.e. call `Application.onCreate`), so everything will be reinitialized. – mxk Apr 11 '12 at 11:25
  • 1
    Singletons are dangerous when used by simpletons. If not managed properly these can easily produce memory leaks – Bostone Jul 05 '12 at 21:13
  • I think its important to keep in mind Edward Falks point above that these singletons are subject to being killed along with the process at any time. I do not agree that onSavedInstanceState should repop the data however. Depending on the application each activity that does not have a `noHistory` flag needs to check if the singletons data is complete (a simple flag solution) and if its not either re-pop the singleton if the data has been persisted _anywhere_ or go back to the `activity` in the stack that would represent the start of the session and therefore can allow the user to rebuild state – Dori Nov 09 '12 at 12:39
  • 2
    One word from the iOS universe .. the equivalent "Application" in the iOS world is indeed ... **precisely a singleton**. Heh! It is **presented exactly** as any other singleton. If I understand the comments from hackbod here, that is **exactly** the case in Android, too ...... except Application is presented with "crappier semantics" - but it's still, exactly, a singleton. (The damned spell checker on my stupid Apple device changed that to 'hacked' BTW, sorry! heh.) – Fattie May 20 '14 at 17:15
  • 2
    @Matthias When the process is killed is not that simple as "Android would simply restart it so everything will be reinitialised". There are problems like Philippe Breault is pointing out here (http://goo.gl/oIbhbx) – Sotti Sep 08 '14 at 13:53
  • @Matthias How about a small github project to show how to do it? It's simpler to understand it:-) – powder366 Apr 26 '16 at 10:51
  • I never appreciated comments like these "it's a bad object-oriented style often embraced by people coming from procedural languages like C". In what language is the JVM implemented in? – Sdr Aug 30 '16 at 00:30
  • @Sriram The idioms of the application platform are completely orthogonal to the idioms used in the platform itself. Following your argument's logic we should all be writing web frontends in C instead of HTML because the browser is written in C. – mxk Aug 30 '16 at 08:26
  • @Matthias Well I agree with you but I wasn't the one who started generalizing stuff (in your case about C programmers who transitioned to Java) which is honestly speaking a little sad and doesn't carry any solid proof. – Sdr Sep 08 '16 at 20:46
  • @Sriram Granted, that comment was inappropriate. Apologies if I offended people. I stand by my point though that carrying over practices and idioms from one language to another is absolutely commonplace, and honestly not unexpected, and I'm not excluding myself here (my first forays into Scala were quite Java-esque...) With singletons specifically programmers proficient in procedural languages find a familiar way of encoding what essentially amounts to global state. I have no proof, no, but have observed it for sure. – mxk Sep 09 '16 at 10:23
  • @Sriram I've edited my response to what I hope is free of potential insults. Thanks for pointing it out! – mxk Sep 09 '16 at 10:27
  • I end up using singletons when diplomacy won't work in Android, they have solved more problems than they create, in fact, I have never suffered any negative effects from using singletons. – Josh Oct 18 '16 at 10:46
234

I very much recommend singletons. If you have a singleton that needs a context, have:

MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

I prefer singletons over Application because it helps keep an app much more organized and modular -- instead of having one place where all of your global state across the app needs to be maintained, each separate piece can take care of itself. Also the fact that singletons lazily initialize (at request) instead of leading you down the path of doing all initialization up-front in Application.onCreate() is good.

There is nothing intrinsically wrong with using singletons. Just use them correctly, when it makes sense. The Android framework actually has a lot of them, for it to maintain per-process caches of loaded resources and other such things.

Also for simple applications multithreading doesn't become an issue with singletons, because by design all standard callbacks to the app are dispatched on the main thread of the process so you won't have multi-threading happening unless you introduce it explicitly through threads or implicitly by publishing a content provider or service IBinder to other processes.

Just be thoughtful about what you are doing. :)

hackbod
  • 90,665
  • 16
  • 140
  • 154
  • 1
    If some time later I want to listen to an external event, or share on a IBinder (I guess that wouldn't be a simple app) I would have to add double locking, synchronization, volatile, right? Thanks for your answer :) – Martín Schonaker Sep 30 '10 at 03:38
  • 2
    Not for an external event -- BroadcastReceiver.onReceive() is also called on the main thread. – hackbod Sep 30 '10 at 18:29
  • 2
    Okay. Would you point me to some reading material (I would prefer code) where I can see the main thread dispatching mechanism? I think that will clarify several concepts at once for me. Thanks in advance. – Martín Schonaker Oct 01 '10 at 14:13
  • 2
    This is the main app-side dispatching code: http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/app/ActivityThread.java – hackbod Oct 02 '10 at 07:21
  • I aggree that there is nothing wrong with Singleton when you define right responsibilities for it. And you should feel comfort to draw singletons in design even if there is no real life-time object instance respresents it in final code. "types" in programming languages is usually good example of singletons as for me. – ony Aug 01 '11 at 20:48
  • Agreed... I would also propose overriding getSystemService() and returning an ondemand instance there. This requires a bit of overhead in creating a MyPersistantObj.from(Context context) method as well as the corresponding getSystemService override but you sort of get the best of two worlds. You can separate your code into a separate Utils type class and you can keep your Application class clean. Downside is every access requires at least a single string comparison. This is also how the Android framework works for LayoutInflator etc. – Maurycy Mar 04 '14 at 22:58
  • 8
    **There is nothing intrinsically wrong with using singletons. Just use them correctly, when it makes sense.** .. sure, precisely, well said. **The Android framework actually has a lot of them, for it to maintain per-process caches of loaded resources and other such things.** Exactly as you say. From your friends in the iOS world, "everything is a singleton" in iOS .. nothing could be more natural on physical devices than a singleton concept: the gps, clock, the gyros, etc etc - conceptually how else would you engineer those than as singletons? So yeah. – Fattie May 20 '14 at 09:52
  • @hackbod Link is broken. – powder366 Apr 26 '16 at 12:45
  • @JoeBlow Could you point me to a line of code in AOSP where this is done? – powder366 Apr 26 '16 at 13:02
  • A bit late but, here is a link to the [ActivityThread.java](https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/ActivityThread.java) source code cloned from AOSP source repo. More specifically, here is the [link](https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/ActivityThread.java#L1315) to the method that actually performs the callbacks for the entire app; this includes, all of the lifecycle events for activities, fragments, and services. – cincy_anddeveloper Aug 11 '16 at 17:40
  • Eventually we are going away from a singleton to virtualization. It gives you a copy of your singleton with desirable flavors, isolate of an actual singleton and gives an ability to share resources wiser. – Singagirl Sep 16 '16 at 23:05
  • 1
    @hackbod Lint says: "Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)" – Filipe Borges Sep 28 '16 at 15:15
  • 1
    I don't know if anyone noticed this, but if you are creating a new instance every-time you call `getInstance()` then, its not really a singleton, Just a static util method. That being said, my understanding can be flawed. Please correct me. – Sanket Berde Oct 01 '16 at 12:29
22

From: Developer > reference - Application

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

Prags
  • 2,457
  • 2
  • 21
  • 38
Somatik
  • 4,723
  • 3
  • 37
  • 49
  • 1
    And if you write an interface for the singleton, leaving getInstance non-static, you can even make the default constructor of the singleton-using class inject the production singleton through a non-default constructor, which is also the constructor you use for crreating the singleton-using class in its unit tests. – android.weasel Jan 20 '13 at 05:41
11

Application is not the same as the Singleton.The reasons are:

  1. Application's method(such as onCreate) is called in the ui thread;
  2. singleton's method can be called in any thread;
  3. In the method "onCreate" of Application,you can instantiate Handler;
  4. If the singleton is executed in none-ui thread,you could not instantiate Handler;
  5. Application has the ability to manage the life cycle of the activities in the app.It has the method "registerActivityLifecycleCallbacks".But the singletons has not the ability.
sunhang
  • 367
  • 2
  • 11
  • 1
    Note: you can instantiate Handler on any thread. from doc : "When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it" – Christ Jun 23 '14 at 07:58
  • 1
    @Christ Thank you!Just now I learned "mechanism of the Looper".If instantiate handler on the none-ui thread without the code 'Looper.prepare()',the system will report the error "java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()". – sunhang Jun 24 '14 at 05:48
11

I had the same problem: Singleton or make a subclass android.os.Application?

First I tried with the Singleton but my app at some point makes a call to the browser

Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));

and the problem is that, if the handset doesn't have enough memory, most of your classes (even Singletons) are cleaned to get some memory so, when returning from the browser to my app, it crashed everytime.

Solution: put needed data inside a subclass of Application class.

Amozoss
  • 1,445
  • 1
  • 11
  • 12
JoséMi
  • 11,642
  • 2
  • 21
  • 25
  • 1
    I often came across posts where peoples state that this may occur. I therefore simply attach objects to the application like singletons with the lazy loading etc. just to be sure that the lifecycle is documented and known. Just be sure to not save hundreds of images into your application object as I understand it will not be cleared from memory if your app is in the background and all activities are destroyed to free memory for other processes. – Janusz Oct 08 '10 at 10:16
  • Well, Singleton lazy loading after application restart is not the right way to let objects be swept by the GC. WeakReferences are, right? – Martín Schonaker Oct 08 '10 at 14:13
  • 15
    Really? Dalvik unloads classes and loses program state? Are you sure it's not that it's garbage-collecting the sort of limited-lifecycle Activity-related objects which you shouldn't be putting into singletons in the first place? You have to give clrar examples for such an extraordinary claim! – android.weasel Jan 20 '13 at 05:23
  • 1
    Unless there have been changes I'm unaware of, Dalvik does _not_ unload classes. Ever. The behavior they're seeing is their process being killed in the background to make room for the browser. They were probably initializing the variable in their "main" activity, which may not have been created in the new process when coming back from the browser. – Groxx Mar 24 '15 at 18:18
5

Consider both at the same time:

  • having singleton objects as static instances inside the classes.
  • having a common class (Context) that returns the singleton instances for all the singelton objects in your application, which has the advantage that the method names in Context will be meaningful for example: context.getLoggedinUser() instead of User.getInstance().

Furthermore, I suggest that you expand your Context to include not only access to singleton objects but some functionalities that need to be accessed globally, like for example: context.logOffUser(), context.readSavedData(), etc. Probably renaming the Context to Facade would make sense then.

adranale
  • 2,835
  • 1
  • 21
  • 39
4

They're actually the same. There's one difference I can see. With Application class you can initialize your variables in Application.onCreate() and destroy them in Application.onTerminate(). With singleton you have to rely VM initializing and destroying statics.

Fedor
  • 43,261
  • 10
  • 79
  • 89
  • 16
    the docs for onTerminate say that it's only ever called by the emulator. On devices that method will probably not be called. http://developer.android.com/reference/android/app/Application.html#onTerminate() – danb Sep 27 '11 at 15:35
4

From the proverbial horse's mouth...

When developing your app, you may find it necessary to share data, context or services globally across your app. For example, if your app has session data, such as the currently logged-in user, you will likely want to expose this information. In Android, the pattern for solving this problem is to have your android.app.Application instance own all global data, and then treat your Application instance as a singleton with static accessors to the various data and services.

When writing an Android app, you're guaranteed to only have one instance of the android.app.Application class, and so it's safe (and recommended by Google Android team) to treat it as a singleton. That is, you can safely add a static getInstance() method to your Application implementation. Like so:

public class AndroidApplication extends Application {

    private static AndroidApplication sInstance;

    public static AndroidApplication getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }
}
didge
  • 316
  • 4
  • 14
RMcGuigan
  • 1,147
  • 2
  • 7
  • 11
3

My 2 cents:

I did notice that some singleton / static fields were reseted when my activity was destroyed. I noticed this on some low end 2.3 devices.

My case was very simple : I just have a private filed "init_done" and a static method "init" that I called from activity.onCreate(). I notice that the method init was re-executing itself on some re-creation of the activity.

While I cannot prove my affirmation, It may be related to WHEN the singleton/class was created/used first. When the activity get destroyed/recycled, it seem that all class that only this activity refer are recycled too.

I moved my instance of singleton to a sub class of Application. I acces them from the application instance. and, since then, did not notice the problem again.

I hope this can help someone.

Christ
  • 450
  • 6
  • 10
2

My activity calls finish() (which doesn't make it finish immediately, but will do eventually) and calls Google Street Viewer. When I debug it on Eclipse, my connection to the app breaks when Street Viewer is called, which I understand as the (whole) application being closed, supposedly to free up memory (as a single activity being finished shouldn't cause this behavior). Nevertheless, I'm able to save state in a Bundle via onSaveInstanceState() and restore it in the onCreate() method of the next activity in the stack. Either by using a static singleton or subclassing Application I face the application closing and losing state (unless I save it in a Bundle). So from my experience they are the same with regards to state preservation. I noticed that the connection is lost in Android 4.1.2 and 4.2.2 but not on 4.0.7 or 3.2.4, which in my understanding suggests that the memory recovery mechanism has changed at some point.

Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • "I noticed that the connection is lost in Android 4.1.2 and 4.2.2 but not on 4.0.7 or 3.2.4, which in my understanding suggests that the memory recovery mechanism has changed at some point." ..... I Would think your devices don't have the same amount of available memory, nor the same app installed. and therefore your conclusion maybe incorrect – Christ Jun 23 '14 at 07:57
  • @Christ: Yes you must be right. It would be strange if the memory recovery mechanism changed between versions. Probably the different memory usage caused the distinct behaviors. – Piovezan Jun 23 '14 at 11:21