Reputation: 797
I have the following DatabaseAccess.java class which contains the following code in order to instance , open , close and some queries :
public class DatabaseAccess {
Context context;
private SQLiteOpenHelper openHelper;
private SQLiteDatabase database;
private static DatabaseAccess instance;
/**
* Private constructor to avoid object creation from outside classes.
*
* @param context
*/
private DatabaseAccess(Context context) {
this.context = context;
this.openHelper = new DatabaseHelper(context);
}
/**
* Return a singleton instance of DatabaseAccess.
*
* @param context the Context
* @return the instance of DabaseAccess
*/
public static DatabaseAccess getInstance(Context context) {
if (instance == null) {
instance = new DatabaseAccess(context);
}
return instance;
}
/**
* Open the database connection.
*/
public void open() {
this.database = openHelper.getWritableDatabase();
}
/**
* Close the database connection.
*/
public void close() {
if (database != null) {
this.database.close();
}
}
However , im getting a serious SONAR warning about this :
Do not place Android context classes in static fields (static reference to DatabaseAccess which has field context pointing to Context); this is a memory leak
In my app , every time I need to use databaseAccess instance I do the following on onViewCreated()
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
databaseAccess = DatabaseAccess.getInstance(getContext());
}
I'm really confused about this , how can I fix this memory leak ?
Upvotes: 0
Views: 241
Reputation: 358
Firstly create an application class for your project like this.
<application android:name="com.xyz.YourApplicataionClassName">
</application>
Then in this application class, create a static getter method for your context. Call this method wherever you need a context.
public class YourApplicataionClassName extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
YourApplicataionClassName.context = getApplicationContext();
}
public static Context getAppContext() {
return YourApplicataionClassName.context;
}
}
Call YourApplicataionClassName.getAppContext() method and this returns your context.
However using Room Persistence Library is better way then doing all this operations
Upvotes: 1
Reputation: 161
Have a look at the developer guidelines for implementing databases within Android here. The issue is that you save the context which is a potential memory leak, mentioned by TDIScott. Here is an example how to create it taken from the guidelines:
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}
If you want a singleton, than do not store the context.
However, I would not recommend to use the SQL Lite implementation directly. ORM libraries or Room specifically are better ways to store data rather than writing the complete boilerplate code around that by yourself. You will find everything you need here.
Upvotes: 0
Reputation: 715
Your getting the error because DatabaseAccess
is created with context. And you have it static, so that object is never collected the Garbage. Hence the error.
Instead of passing activity context to the singleton class, you can pass applicationContext(). and @supress
the warning
Upvotes: 1