2Lines Software
3Aug/1011

Singletons and Services and Shutdowns Oh My

3662945409_1aca357b51

Passing data back and forth between activities on the Android platform is one of the more challenging aspects of understanding Android. Understanding how this data is managed by the OS is the difference between getting flooded with Error Reports and bad reviews and getting  glowing praise and eternal gratitude. Well maybe not to that extent, but having a good background in passing data can make your code much easier to manage and cleaner to read (and for that you have my gratitude) So in passing the data there are essentially two types Persistent and strangely enough, Non-Persistent data types. The Persistent types are best handled by preferences, files, databases or content providers and they are pretty detailed in their operation. If you need to keep data over the length of more that one session consider using Persistent data stores. On the other hand, there are often times where transient data needs to be stored for one session and passed between activities. To handle that there are a couple of ways to handle it. This page details some of the methods, and it is repeated here for convenience;

How do I pass data between Activities/Services within a single application?

It depends on the type of data that you want to share:

Primitive Data Types

To share primitive data between Activities/Services in an application, use Intent.putExtras(). For passing primitive data that needs to persist use the Preferences storage mechanism.

Non-Persistent Objects

For sharing complex non-persistent user-defined objects for short duration, the following approaches are recommended:

The android.app.Application class

The android.app.Application is a base class for those who need to maintain global application state. It can be accessed via getApplication() from any Activity or Service. It has a couple of life-cycle methods and will be instantiated by Android automatically if your register it in AndroidManifest.xml.

A public static field/method

An alternate way to make data accessible across Activities/Services is to use public static fields and/or methods. You can access these static fields from any other class in your application. To share an object, the activity which creates your object sets a static field to point to this object and any other activity that wants to use this object just accesses this static field.

A HashMap of WeakReferences to Objects

You can also use a HashMap of WeakReferences to Objects with Long keys. When an activity wants to pass an object to another activity, it simply puts the object in the map and sends the key (which is a unique Long based on a counter or time stamp) to the recipient activity via intent extras. The recipient activity retrieves the object using this key.

A Singleton class

There are advantages to using a static Singleton, such as you can refer to them without casting getApplication() to an application-specific class, or going to the trouble of hanging an interface on all your Application subclasses so that your various modules can refer to that interface instead. But, the life cycle of a static is not well under your control; so to abide by the life-cycle model, the application class should initiate and tear down these static objects in the onCreate() and onTerminate() methods of the Application Class [my emphasis]

Being as I come from a java EE background the first decision was to use the singleton class and allow the instance to be available across the VM. The singleton design pattern is fairly well-known and is a good easy way to manage control across many activities. In some previous projects I have used them to manage HTTP connections, image caching and global application configuration to much success. However, this is the important part to consider when using singletons which is very important; Android OS can and will terminate your singleton and not even tell you about it. I highlighted that in bold because if your design depends on singleton patterns you naturally assume they are going to stay persistent through the VM. These are frustrating errors and difficult to track down and even more frustrating for your users. For instance consider this piece of code: In your main activity;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SuperSingletonManager.create(this);
}

And your singleton;

private static SuperSingletonManager instance;
private SuperSingletonManager(Context context)
{
// do stuff once
}
protected static SuperSingletonManager create(Context context) {
instance = new SuperSingletonManager(context);
}
protected static SuperSingletonManager getInstance() {
if (instance == null)
throw new NastyException("Oh God Why?");
return instance;
}

Seemingly you should be able to call  SuperSingletonManager.getInstance() at any time and get access to the static instance. However, this isn't the case. If the launching  activity is removed by the OS (it happens, a lot) while you are on another activity, that static instance will be gone. So when you make that  SuperSingletonManager getInstance() call you are only going to get a nasty exception. This also means that if any of your functions in SuperSingletonManager make use of the Context those will throw errors. Ack. But I really, really like singletons. So do I. And far be it from me to tell you how to architect your code. The only stipulation is that the singleton should abide by the lifecycle model. We can do this by launching the singletons from a service and binding that service to the launching activity. To the Android purists, and common-sensists out there you might just say "Why not just use a service instead of a singleton?".  Sure, makes sense but this post is about singletons and how to get them working and not common-sense. So here is the class that will do all that;

public class SingletonService extends Service {

private final ISingletonService.Stub mBinder = new ISingletonService.Stub() {

public void startSingletons() throws RemoteException {

initializeSingletons();

}

public void stopSingletons() throws RemoteException {

shutdownSingletons();

}

};

public IBinder onBind(Intent intent) {

return mBinder;

}

protected void initializeSingletons() {

SuperSingletonManager.initialize(getApplicationContext());

}

private void shutdownSingletons() {

SuperSingletonManager.shutdown();

}

}

When you start your main activity bind the service using bindService() , and make a call to the startSingletons() method. This will launch your singletons under the lifecycle of the service. This will ensure they are active for the life of your application session. Also, make sure to unbindService when you are finished. Nobody likes developers that don't clean up after themselves. Good luck and if you actually use this method let me know! John

Posted via email from John Carpenter

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]
  • Ritwaj

    Great post! I have been looking into exactly this issue for quite some time now. I want to share few utility functions across my application at a central location, and deriving from J2EE environment , wanted to make that class a Singleton.

    Making Singleton a service is a great idea (which did not occur to me). However, I stumbled upon this discussion http://stackoverflow.com/questions/3826905/singletons-vs-application-context-in-android and was quite happy with it.

    What do you feel about subclassing android.os.Application to achieve the same? and how would you compare this approach with yours.

    [I guess, I'll end up using your trick :P ]

  • http://pradabag0.journalspace.com/ Replica Prada Bags

    Thank you so much designed for authoring this particular, I stumbled upon the idea to always be truly informative, therefore responded tips complications I’d.

  • HighFlyer

    Thanks a lot! I’ve faced problem one day before release and you help me so much!

  • Alexey

    May you provide link to official documentation of DalvikVM or Android for this sentense:
    “Android OS can and will terminate your singleton and not even tell you about it”

  • john

    From here:
    http://developer.android.com/guide/topics/fundamentals.html#acttask

    They mention, “Each process has its own virtual machine (VM), so an application’s code runs in isolation from other applications.” So the singleton is tied to the VM, which is tied to the activity. Its a good system for isolating processes and ensuring that no other application can hijack another.

  • Alexey

    Thank you, John. Help me to understand.

    Provided documentation says that whole application lives in own VM, not separate Activity. As I guess, Service should live in same VM as activity (its not true?), so I don’t understand why singleton would not be killed in that case.

  • john

    It is slightly confusing as most of the operations happen within the dalvik VM. Here is what I think is happening.

    1. When a new application starts up, a new dalvik VM is started. That VM is responsible for GC, class loading and lifecycle.
    2. Each activity or service started runs within the dalvik VM. When you start a singleton it is tied to either the activity or the service.
    3. When the activity/service is no longer processing it is sent to the activity stack.
    4. If the VM runs low on memory, it will have to forcibly terminate any old activity or service. At this point I suspect that if the singleton is loaded in the class loader with the activity, the singleton class is unloaded making the static instance null.

    So without a lot of other research on this I am just guessing as to why that is happening. By binding the singletons to the service isolates the static variables within the service and not any container activity.

    Two other methods would be to either override the Application class and assign the static variables there, or create a service instead of using a singleton.

    I know I mentioned that I love singletons but in the interest of disclosure I completely avoided them in my latest project and elected to go with a service instead. So far no problems with it.

  • Alexey

    Thanks again for detailed answer.

    I faced singleton problem few weeks ago. Temporary solution was storing data in Application object and passing it for all objects that required it.

    Temporary because system may recreate Application object and destroy all previously loaded data while user walking through activities. This behavior was surprising. I thought Application object may die only with Activities stack.

    So we decide to reload necessary data if needed. It makes code more complicated but app become more stable.

    Ill try your solution with service as soon as possible, but i have a lot of doubts about its workable for our case.

    Thanks a lot for discussion :)

  • kaay

    This info is old. The linked page has changed, and no longer refers to the Application object as an option to store things in.
    Also, I don’t know when the part about using the “onCreate() and onTerminate() methods of the Application Class” was ever a good idea, as onTerminate “will never be called on a production Android device, where processes are removed by simply killing them”

  • http://www.facebook.com/peter.lindhard Peter Lindhard

    Great comment, can you say what options are available? I found this article well written and argumented…. I need to share user cache across activities, and store them in a sqlite db… A lazy loading singleton is out, and you say the application extension is out, whats left for mortals?

  • Alexander Wolf

    thanks, this helped a lot. I have redone everything using a Service now. I would have used your model but its missing too much information to be used as is.