package edu.vandy.common; import java.util.HashMap; import java.util.Map; import android.util.Log; /** * Defines a generic singleton class whose instance() method ensures * only one object of type Class<T> is created. We need this class * since Java Generic don't support proper singletons (a la the * "Gang-of-Four" book). More information about this approach appears * at http://neutrofoton.com/generic-singleton-pattern-in-java. */ public class GenericSingleton { /** * Debugging tag used by the Android logger. */ protected final static String TAG = GenericSingleton.class.getCanonicalName(); /** * The singleton field. */ private static final GenericSingleton sInstance = new GenericSingleton(); /** * This HashMap ensures only one object of type Class<T> is * created. */ @SuppressWarnings("rawtypes") private Map<Class, Object> mMap = new HashMap<>(); /** * Return the one and only instance of Class<T>, which is created * on-demand if it doesn't exist. */ @SuppressWarnings("unchecked") public static <T> T instance(Class<T> classOf) { // Ensure thread-safety. synchronized(sInstance) { // Try to get the one and only instance of Class<T> that's // stored in the map. T t = (T) sInstance.mMap.get(classOf); // Check to see if this is the first time a request for an // instance of Class<T> has been occurred. if (t == null) { try { // If this is the first time in then create a new // instance of Class<T>. t = classOf.newInstance(); } catch (Exception e) { Log.d(TAG, "GenericSingleton.instance() " + e); t = null; } // Store the new instance of Class<T> in the map so // it'll be available next time instance() is called. sInstance.mMap.put(classOf, t); } // Return the one and only instance of Class<T>. return t; } } /** * If @a classOf is in the singleton map then set it to null so * it's cleaned up properly by the garbage collector. * * @return True if @a classOf is found/removed, else false. */ public static <T> boolean remove(Class<T> classOf) { synchronized(sInstance) { // Try to get the one and only instance of Class<T> that's // stored in the map and if it's found, set it to null so // it will be garbage collected. if (sInstance.mMap.get(classOf) != null) { sInstance.mMap.put(classOf, null); return true; } else return false; } } /** * Disallow instantiation. */ private GenericSingleton() {} /** * Disallow cloning. */ public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }