This question already has answers here:
Are fields initialized before constructor code is run in Java?
(5 answers)
Closed 12 months ago.
Hi I have the following code and as I am stepping through it in the debugger I notice that the constructor does not get invoked and hence mContext variable initiated within it remains null.
As I am stepping through the debugger the getInstance() function will call the constructor RaceTimeDataContract(Context context), however if I try to step into the constructor it does not and instead the debugger steps to the line where TABLE_NAME is being initialized. The problem is since mContext remains null, then exception is being thrown.
Anyone know what may be causing this behavior? Code is below:
public class RaceTimeDataContract implements BaseColumns{
private static RaceTimeDataContract sInstance;
private static Context mContext;
private RaceTimeDataContract(Context context) {
this.mContext = context; // This is not getting called
}
private RaceTimeDataContract(){}
public static RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
// mContext remains null and forces a exception
private final String TABLE_NAME = mContext.getResources().getString(R.string.table_name);
Appreciate any feedback!
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.
Related
Currently, I have a class whose constructor takes a username, password, and Context. I would like to be able to access this object from anywhere, so I was thinking of implementing a singleton pattern.
The current constructor uses the credentials passed in to authenticate future api calls through that class. If I were to implement the singleton pattern, my first thought would to be have the getInstace() method take a username, password, etc.., but it seems wrong to have to pass that info everytime i grab an instance. Because of this I was thinking of adding some sort of .authenticate(usr, pswrd) method to be called when grabbing the first instance.
My question is, is this the correct approach? If not, what would be a good way to handle this? Heres the current code:
constructor:
public Play(String username, String password, Context context) {
api = getApi(username, password);
Intent intent = new Intent(context, MyService.class);
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
//check if first run
//if so, call api for info and store locally
//if not, update as needed
SharedPreferences pref = context.getSharedPreferences("pref", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
if (pref.getBoolean("first_run", true)) {
loadInitialData(context);
}
editor.putBoolean("first_run", false);
editor.commit();
}
Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine. The singleton class must provide a global access point to get the instance of the class. Singleton pattern is used for logging, drivers objects, caching and thread pool
This code is not tested but should give you an idea how you can use singleton pattern while using SharedPrefrencess.
Constructor is private, So only getInstance() method can access the instance, so you will create an instance of this class if it doesn't exists or if instantiated previously use that instance
synchronization is required to make sure when multiple thread are trying to make a instance for the first time
import android.content.Context;
import android.content.SharedPreferences;
/**
* Created by Pankaj Nimgade on 23-05-2016.
*/
public class Play {
/**
* volatile keyword ensures that multiple threads handle the uniqueInstance
* variable correctly when it is being initialized to Singleton instance
*/
private volatile static Play play;
private static final String XML_FILE = "play_xml_file.xml";
private static final String KEY_DATA = "SOME_DATA_KEY";
private static final String KEY_USERNAME = "SOME_USERNAME_KEY";
private static final String KEY_PASSWORD = "SOME_PASSWORD_KEY";
private static SharedPreferences sharedPreferences;
private static SharedPreferences.Editor editor;
private Play() {
}
public static Play getInstance(Context context) {
if (play == null) {
synchronized (Play.class) {
if (play == null) {
sharedPreferences = context.getSharedPreferences(XML_FILE, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
play = new Play();
}
}
}
return play;
}
public boolean saveSomeData(String someData) {
editor.putString(KEY_DATA, someData);
return editor.commit();
}
public String readSomeData() {
return sharedPreferences.getString(KEY_DATA, "default Value");
}
public boolean saveUserNameData(String username) {
editor.putString(KEY_USERNAME, username);
return editor.commit();
}
public String readUserNameData() {
return sharedPreferences.getString(KEY_USERNAME, "default username Value");
}
public boolean savePasswordData(String password) {
editor.putString(KEY_PASSWORD, password);
return editor.commit();
}
public String readPasswordData() {
return sharedPreferences.getString(KEY_PASSWORD, "default password value");
}
}
in this above approach I am making instance creation of the class lazy, as the instance will only be created if demanded, although the code is thread safe and will work on all Java version you may want to consider different approach to implement this if you are using Java 5 and above.
https://sourcemaking.com/design_patterns/singleton/java/1
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
The inner class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that getInstance() is called. Thus, this solution is thread-safe without requiring special language constructs (i.e. volatile or synchronized).
I constructed an SQL Lite handler class which extends SQLiteOpenHelper:
public class DatabaseHandler extends SQLiteOpenHelper
The class have this constructor:
public DatabaseHandler(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
How can i use this class from multiple activites? that is throuhout my entire app?
When i try to instantiate the class from another activity it gives an error because the context is wrong.
What is the best practice for excessing a db from multiple activities?
Each activity should have its own instance of SQLiteDatabase.
See Do I need to call getWritableDatabase() everytime I manipulate data for more discussion on the subject, including example code.
Take a global static
Utils.class
public static DatabaseHandler data;
SplashActivity.class
Utils.data=new PortfolioDatabaseManager(getBaseContext());
You can use it as per your need in any class by accessing like:
Utils.data
You can add getReadDatabase & getWriteDatabase in database class:
public SQLiteDatabase getReadDatabase(Context context){
// create or open the database
DatabaseHandler helper = new DatabaseHandler(context);
SQLiteDatabase data = helper.getReadableDatabase();
return data;
}
public SQLiteDatabase getWriteDatabase(Context context){
// create or open the database
DatabaseHandler helper = new DatabaseHandler(context);
SQLiteDatabase data = helper.getWritableDatabase();
return data;
}
You can extend the class with the Application class and after that you can use all the members and functions of that class from any of the activity. You can make your class a member of the Global class and use it in whole application.
Like this :
class Global extends Application
{
........
........
}
When managing persistent data, the best practice in OOP is the use of the "Gateway Pattern".
Gateways encapsulate and centralizes the application database for easier access.
public class OfflineGateway(){
private static OfflineGateway instance;
private Activity activity;
private OfflineGateway(){
//some initialization
}
public static OfflineGateway getInstance(Activity activity){
if(instance == null)
instance = new OfflineGateway();
return instance;
}
//private accessible methods
private String getStringData(){
//do something here
}
private void setStringData(String string){
//do something here
}
}
I am relatively new to android development and being from a c# background it is entirely possible my entire strategy is wrong, but I am continually getting warned by Eclipse when degugging that I haven't closed a database connection properly causing a memory leak.
I have a base database class that extends SQLiteOpenHelper:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
public MySQLiteOpenHelper(Context context) {
this(context, "myDb", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE MyTable (A INT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public Cursor executeSelect(String sql, String[] parameters) {
return getReadableDatabase().rawQuery(sql, parameters);
}
}
A generic entity:
public class MyClass {
private int a;
public void setA(int value) {
this.a = value;
}
public int getA() {
return this.a;
}
}
And essentially a service for MyClass (although in reality this extends a generic abstract class for reusability purposes)
public class MyClassService {
private MySQLiteOpenHelper helper;
private Context context;
public MyClassService(Context context) {
this.context = context;
}
private MySQLiteOpenHelper getHelper() {
if (helper == null) {
helper = new MySQLiteOpenHelper(this.context);
}
return helper;
}
public void dispose() {
if (helper != null) {
helper.close();
helper = null;
}
}
public ArrayList<MyClass> getAll()
{
ArrayList<MyClass> list = new ArrayList<MyClass>();
Cursor cursor = getHelper().executeSelect("SELECT A FROM MyTable", new String[0]);
while (cursor.moveToNext()) {
MyClass item = new MyClass()
item.setA(cursor.getInt(0));
list.add(item);
}
cursor.close();
return list;
}
}
So, my question is when I use a line of code like this from an Activity:
ArrayList<MyClass> list = new MyClassService(this).getAll();
is the instance of MyClassService disposed of immediately, or could this be the source of my memory leaks.
Would I be better calling the full code to ensure the database is closed using the dispose method?
MyClassService svc = new MyClassService(this);
ArrayList<MyClass> list = svc.getAll();
svc.dispose();
The Garbage Collector would be able to collect your class, as well as the Helper class, since these are no longer part of the Object chain (not a technical term - just something I made up). However, you would still need to explicitly close the database (if you don't this would definitely be your memory leak culprit). As it stands, you can do this in your Object's finalize() method, which is called during garbage collection:
#Override
public void finalize() {
dispose();
}
I usually prefer, however, to do things a little differently. Data Stores like this are often best written as Singletons, since they may be accessed by multiple classes, and if different instances are created they will still open a new access point for reading a writing, and could cause many issues. You sort of have a singleton-style setup in that there is one helper variable in your code, but you may want to simply make your Helper class the singleton. You can do this by removing your constructors and adding this:
private static MySQLiteOpenHelper self;
private MySQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
private MySQLiteOpenHelper(Context context) {
this(context, "myDb", null, 1);
}
public static MySQLiteOpenHelper sharedHelper(Context context) {
if (self == null)
self = new MySQLiteOpenHelper(context);
return self;
}
Then, instead of keeping track of a helper object in MyClassService using getHelper(), you can get THE helper using:
MySQLiteOpenHelper.sharedHelper(context);
The benefit of doing this means you only have to keep track of one Helper throughout the entire app, and in the helper's finalize() method, you can now close the database. This will be called when the app process is killed, and prevent any memory leaks:
public void finalize()
{
close();
}
You should explicitly call dispose - not doing so won't cause a memory leak (the object can be collected immediately after new MyClassService(this).getAll() because there aren't any live references to the object), but may cause your database to run out of available connections.
You forgot to call close on the database object returned from getReadableDatabase().
It's just something that puzzles me. Is it possible to use the current instance of the class within the constructor?
I've created a BroadcastReceiver that registers itself with the context within the constructor of the BroadcastReceiver. In addition it will unregister again. Is this good style?
Here's my example:
public class MyBroadcastReceiver extends BroadcastReceiver {
protected Context context;
protected MyOnBroadcastReceivedListener listener;
protected int receiverId;
protected String receiverTag;
public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
super();
this.context = context;
this.listener = listener;
this.receiverId = receiverId;
this.receiverTag = receiverTag;
IntentFilter intentFilter = new IntentFilter(receiverTag);
context.registerReceiver(this, intentFilter); // <--- Look at the use of this here
}
public void detach() {
if (context != null) {
context.unregisterReceiver(this); // <--- Look at the use of this
}
}
#Override
public void onReceive(Context context, Intent intent) {
// ...
if (listener != null) {
listener.onBroadcastReceived(receiverId, "Bla", "Blub");
}
}
}
Yes, no trouble at all.
Inside the constructor, the object has been created but still no reference has been returned to the rest of the java code. You can use this without worries.
Anyway, in some frameworks where some attributes may be initialized automatic (Context Dependent Injection, CDI), it is not possible to fully initialize the class in the constructor (because such attributes are still not available and may be needed). These frameworks rely in that you mark a method as #PostConstruct; after all attributes are set that method will be called (just so you know what it means when you find it).
If you refer to using this in constructor code, then yes - it is perfectly valid, otherwise constructor would not be really able to construct to much within own instance. I'd however suggest following common practice and prefix your class members (most commonly used prefix is 'm') which helps avoid problems which are sometimes hard to debug. So instead of:
protected Context context;
protected MyOnBroadcastReceivedListener listener;
you would have:
protected Context mContext;
protected MyOnBroadcastReceivedListener mListener;
You can do this, but is not a good style. Passing this from inside a class constructor is dangerous as the current, still constructing object might not be fully intialized.
For example, you might one day add a new int field to the MyBroadcastReceiver, but overlook that you have the statement context.registerReceiver(this, intentFilter); and add the intialization of the new field at the end of the constructor:
public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
super();
this.context = context;
this.listener = listener;
this.receiverId = receiverId;
this.receiverTag = receiverTag;
IntentFilter intentFilter = new IntentFilter(receiverTag);
context.registerReceiver(this, intentFilter); // <--- Look at the use of this here
this.newField = 1;
}
Now, you might expect that in the Context.registerReceiver method the newField to be 1 as it initialized in the MyBroadcastReceiver constructor. But you will get the value 0.
See also the following SO question for more information and more potential problems that could appear: Passing "this" in java constructor
Yes it works. I tried a simple test case. and it works. :
public class Test {
private int variable;
private Test2 test2;
public Test(int variable, Test2 test2) {
this.variable = variable;
this.test2 = test2;
test2.printTest(this);
}
public int getVariable() {
return variable;
}
public static void main(String[] args) {
Test test = new Test(111111,new Test2());
}
}
class Test2{
Test2() {
}
public void printTest(Test test){
System.out.println(test.getVariable());
}
}
And it works like a charm
Where it is better to initialize fields? In constructor (var.1) or on declaration (var.2)?
var. 1
public class UtilWebLoading {
private int data;
private Context context;
public UtilWebLoading(Context context) {
this.context = context;
data = 100;
}
...
}
var. 2
public class UtilWebLoading {
private int data = 100;
private Context context;
public UtilWebLoading(Context context) {
this.context = context;
}
...
}
In var. 1 the context has been initiated, while in var. 2 it will be null!
Use the first one.
I personally prefer to initialize fields when I have sufficient context to do so. For example, if I have a List field I usually initialize it upon declaration (unless the class requires the user to pass an implementation of their choosing), but if I have an array that requires a size to be passed, I'm forced to wait for a constructor call.
Hence, in your case, the second snippet does not have enough context to initialize Util at declaration, because no valid Context member exists.