views:

377

answers:

6

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 have both mechanisms?

To be honest, I expect the same answer in this post http://stackoverflow.com/questions/2709071/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

Thanks in advance.

A: 

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
+3  A: 

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
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 :)
mrrtnn
Not for an external event -- BroadcastReceiver.onReceive() is also called on the main thread.
hackbod
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.
mrrtnn
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
Thank you so much.
mrrtnn
A: 

Here is a nice post about singletons in Android. Singleton objects doesn't behave exactly same in DalvikVM as they behave in JVM.

bhups
I found something confusing in that post. Android page states that you don't have to cast to the Application subclass. But the post tells to do a bindService call, which implies a cast to IBinder... :SWell, my first impression is that it's way much work to do it with singletons than with App. Besides, if you forget an unbind, you could incur in a mem leak, right?Thanks for you answer!
mrrtnn
+2  A: 

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.VIEW_ACTION, 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.

JoséMi
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
Well, Singleton lazy loading after application restart is not the right way to let objects be swept by the GC. WeakReferences are, right?
mrrtnn
+4  A: 

I very much disagree with Dianne Hackborn (and yes, I realize she's an Android framework engineer, thanks.) 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 often embraced by people coming from procedural languages like C, where it is common to maintain 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.

Matthias
A: 

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