0

I am building a singleton service in Java for Android:

final class MyService {

    private static Context context = null;
    // ...

    private MyService() {
        myObj = new MyObj(context);
            // ...  
    }                       
    private static class Singleton {
        private static final MyService INSTANCE = new MyService();
    }

    /**
     *  a singleton - do not use new(), use getInstance().
     */
    static synchronized myService getInstance(Context c) {
        if (context == null) context = c;
        return Singleton.INSTANCE;
    }

To improve performance I use static variables and methods throughout.

My questions:

  • for objects, new() ensures the opportunity to initialize that object before its use. Is there an equivalent for a static class? For example: when static methods depend upon earlier initializations - such as as for 'context' above - is there a means of ensuring that the initialization happens first? Must I throw an exception if they have not?

  • as this is all static I expect that there is only the class itself: is that a singleton by definition? Is the recommended code above just the way of preventing instantiation of objects?

Thanks in advance!

DJC
  • 3,243
  • 3
  • 27
  • 31
  • All services in android are singletons, what are you trying to accomplish? – Falmarri Sep 24 '10 at 19:47
  • 2
    I would advise against making your singletons stateful (adding context). Those two things are two heavily conflicting anti-patterns. – Mark Peters Sep 24 '10 at 19:49
  • @Falmarri: I am trying to accomplish 1) ensuring a single authoritative source of some methods, 2) maximizing performance. I imagine this is similar to getSystemService() but within a single process (and thus does not need AIDL). My approach so far is to extend Service and then call its methods directly from within other application components (without using intents). – DJC Sep 24 '10 at 20:09
  • @Mark: My service tracks events and offers summaries via getters. This is clearly stateful and also seems a viable candidate for a singleton. Is this an exception - or can you suggest where I might learn more about the anti-pattern? Thx! – DJC Sep 24 '10 at 20:14
  • @Falmarri: I need to add .. my service is runs periodically via an alarm to gather event data and summarize it. That data needs to be available at any time - for example when a widget reads it. I've had my service in memory "permanently" serving the widget, but it occurs to me that I ought to be decoupling these: a periodically run service writing summary data to a content provider, which in turn is read by callers. /me suffers noobish confusion :) – DJC Sep 24 '10 at 20:31
  • `I've had my service in memory "permanently"` That's not possible in android. Android is free to kill any running process for any reason at any time. If you want to preserve data, you either need to use a shared preference or a database. Or a content provider. – Falmarri Sep 24 '10 at 20:42
  • I don't mean to give offense, but I think you're taking this whole thing too far. You seem to be wanting to needlessly improve speed simply for the sake of needlessly improving speed. Keep in mind that the more complex your code, the more maintenance is required; especially if other developers are/become involved with the project. I think your time could be better utilized elsewhere. – Andrew Sep 24 '10 at 21:55
  • Making a method static doesn't make it faster. – Skip Head Sep 24 '10 at 21:59
  • @DJC: You are leaking memory by holding an arbitrary `Context` in a static data member, with no apparent plan to `null` it out when that `Context` is destroyed. Your perceived performance gains, if they exist at all in Dalvik, will be on the order of microseconds per call. That is no justification for holding onto a `Context` after it has been destroyed. Unless you have used Traceview and concluded that these microseconds are indeed critical to your app's performance, what you are doing is premature optimization. – CommonsWare Sep 25 '10 at 01:34
  • tyvm to all for your feedback... it's clear I have a deep misconception or two to correct. My (perhaps premature) considerations for performance on this platform devolved into a broader issue: regarding "static" as a means of simplifying a singleton by declaring that "there is only one of this... and this... and..." I adopted this as a general principle similarly to how one adopts the general use of "private" to minimize scope, coupling, and side-effects. I am missing how such complicates. – DJC Sep 25 '10 at 18:15

3 Answers3

2

That's certainly one way to create a singleton. I think you could do away with the static helper; going static for performance reasons really doesn't save much and it obfuscates the code.

I think your real question is whether construction of a static can be delayed until context is not null. The answer depends on the VM; in most "vanilla" Java VMs, INSTANCE would not actually be instantiated until the first call to GetInstance(); statics are lazily evaluated for better startup performance. That means that as long as context got something else before the first call to GetInstance(), you're good.

However, forgive me but I do not know if this behavior differs in the Android VM, which is technically not a "real" Java VM (or so says Sun/Oracle). To be on the safe side, if context doesn't have an instance by the time the static constructor is called, I would look into resolving one in the static constructor using a static factory method or a simple IoC, before instantiating INSTANCE.

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • I am composing objects and within them I instantiate and use android classes that require context (e.g. getSharedPreferences). I was using a singleton 'with static' model, thus exposing methods for use without any prior call to getInstance() and the initializations it performs. It seems my first step forward is to abandon 'static' so that getInstance() is ensured - and to study up on when it is proper to use it. Thanks lots to all for helping debug my broken concept! – DJC Sep 25 '10 at 18:36
  • The VM spec is very specific about the situations in which statics are initialized. While Dalvik is definitely not Java(tm), it does try to follow the rules laid out in the specification. – fadden Sep 27 '10 at 20:20
1

You can add a static initialisation block to your class

public class MySingleton {
    /* Default constructor */
    private MySingleton() {
    }

    static {
          //Static init stuff...
        }
        ...
    }
}

The static initializer block will be called once for each classloader the class is loaded by - so typically, only once during the life of the process.

Finally, by definition your singleton is only going to be created once so there will be no performance benefit from using static helpers to do the job.

Robert Christie
  • 20,177
  • 8
  • 42
  • 37
  • Robert, according to my O'Reilly, "if a method is declared with the final{or static] modifier, ... the compiler knows that there is only one version of the method, and dynamic method lookup is not necessary ... and are candidates for inlining ..." Maybe that's what you said? :D – DJC Sep 24 '10 at 21:00
  • DJC - Sure, but as this case is initailisation for a singleton, the JIT won't bother inlining the call as it's only called once. – Robert Christie Sep 24 '10 at 21:29
0

Avoid overengineering. Use an enum instead.

While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.

Joshua Bloch

The approach is explained in this post by Joshua Bloch.

Community
  • 1
  • 1
  • You can also check answers to this StackOverflow question : https://stackoverflow.com/questions/70689/what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java – RolandMinten Nov 08 '18 at 09:48