When creating new instances, inline field initialisation is performed before the constructor is called. One simple fix in your case is to move the field initialisation into the constructor after the context is set
e.g. (I've reorganised the code a little, and dropped the this
on mContext
since it is a static member)
public class RaceTimeDataContract implements BaseColumns {
private static RaceTimeDataContract sInstance;
private static Context mContext;
public static RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
private final String TABLE_NAME;
private RaceTimeDataContract(Context context) {
mContext = context;
this.TABLE_NAME = mContext.getResources().getString(R.string.table_name);
}
// The below is invalid as it doesn't set TABLE_NAME and should probably be removed
// private RaceTimeDataContract(){}
}
The above isn't very idiomatic and would be better re-arranged to support a singleton better. There are many ways to do this but some general things which would be a benefit are
- Storing the context on the instance object, and not statically
- Preventing race conditions on
getInstance
- Removing the default constructor
Assuming you don't retrieve the instance often this can easily be accomplished by synchronising on the getInstance
call. e.g.
public class RaceTimeDataContract implements BaseColumns {
private static RaceTimeDataContract sInstance;
public static synchronized RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
private final Context mContext;
private final String tableName;
private RaceTimeDataContract(Context context) {
this.mContext = context;
tableName = mContext.getResources().getString(R.string.table_name);
}
}
As a last note it is atypical of a singleton to take a parameter in the getInstance
method but always return the same object - you can imagine in this case that if getInstance
is called a second time with a different context then we get the original instance which may have an incorrect table name.
If you do need a singleton per context you can store each instance per context in something like a Map<Context, RaceTimeDataContract>
, probably using a ConcurrentHashMap
, and it would be better to think of it as some kind of reference cache or factory rather than a singletone.
If possible, it is better to just have a zero parameter getInstance
method which can retrieve the singleton context statically the first time it is required. This can open your class up to more typical/simpler singleton patterns like enum singletons and static singleton holders.