Memory leaks in context - android

I have a class App which extends Application and has a static method which returns context(which is static).
public class App extends Application {
private static Context context;
#Override
public void onCreate() {
super.onCreate();
context = this.getApplicationContext();
DBHelper dbHelper = new DBHelper();
DatabaseManager.initializeInstance(dbHelper);
}
public static Context getContext() {
return context;
}
}
Now in the DBHelper class which extends SQLiteAssetHelper in the constructor, i have this:
public DBHelper() {
super(App.getContext(), DATABASE_NAME, null, DATABASE_VERSION);
}
This is the DataBaseManager class:
public class DatabaseManager {
private Integer mOpenCounter = 0;
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return instance;
}
public synchronized SQLiteDatabase openDatabase() {
mOpenCounter+=1;
if(mOpenCounter == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
}
Everything works fine, but there is a design problem because context fields should not be static. How do I use a context in DBHelper while keeping the code working and the field non-static?

You can pass ApplicationContext inside the DBHelper constructor like below:
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
and then
DBHelper dbHelper = new DBHelper(getApplicationContext());

Related

how to design lazy holder pattern in android with arguments?

I wanna know how to design lazyholder singleton pattern with arguments.
I know only when no argument there is but dont know with arguments.
the problem is like below when construct private static final DBHelper INSTANCE = new DBHelper();
how can I solve it?
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context=context;
}
public static DBHelper getInstance(){
return DBHelper.DBHelperHolder.INSTANCE;
}
private static class DBHelperHolder{
private static final DBHelper INSTANCE = new DBHelper();
}
You can use DCL pattert, for example:
public class DBHelper {
private static volatile DBHelper instance;
public static DBHelper getInstance(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
if (instance == null) {
synchronized (DBHelper .class) {
if (instance == null) {
instance = new DBHelper(context, name, factory, version);
}
}
}
return instance;
}
}
But you need to supply arguments every time you call getInstance.
In addition to #Bracadabra's answer,
It is recommended to add private constructor() as it is singleton pattern and we want to restrict new object creation of our class DBHelper
I prefer LOCK object for synchronisation (to be thread safe)
We should restrict clone() calls also, so that outside code can not clone this class by .clone() call. So, override clone() method and return CloneNotSupportedException() from it.
public class DBHelper {
private static DBHelper instance;
// LOCK object for synchronisation
private static Object LOCK = new Object();
// Private Constructor
private DBHelper() { }
public static DBHelper getInstance(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
if (instance == null) {
synchronized (LOCK) {
if (instance == null) {
instance = new DBHelper(context, name, factory, version);
}
}
}
return instance;
}
#Override
protected DBHelper clone() throws CloneNotSupportedException {
return CloneNotSupportedException();
}

Android: understand this.context

I am trying to understand a class responsible to make a connection to a DB
the code is:
public class DBAdapter
{
final Context context;
DatabaseHelper DBHelper;
SQLiteDatabase db;
public DBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//All the necessary method are implemented.
}
}
So to make a conection i should just"
DBAdapter db=new DBAdapter(this);
My question is what does this line this.context = ctx; does:
Why we can not omit that and simply :
public DBAdapter(Context ctx)
{
DBHelper = new DatabaseHelper(ctx);
}
Through this keyword you are specifying that the address or the reference of activity class which is coming to the DBAdapter method in ctx variable which is of Context type will be assigned to class level Context variable.
Though you can remove class level variable and this.context = ctx; line and simply write as you had specified
public DBAdapter(Context ctx)
{
DBHelper = new DatabaseHelper(ctx);
}
but if you want to use ctx (context reference) value to all over class it is advised to use class variable.
According to your class code. you does not required to assign context to another context variable . this is simplified code.
public class DBAdapter
{
DatabaseHelper DBHelper;
SQLiteDatabase db;
public DBAdapter(Context ctx)
{
DBHelper = new DatabaseHelper(ctx);
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//All the necessary method are implemented.
}
}
To assign context to another variable is useful when you use context in some other methods as well. because the scope of the variable is limited to its method. you cannot use it outside of the constructor(according to your code)
If you're following the tutorial, they have a Context class variable because they reference it in the open method.
public DbAdapter(Context ctx)
{
this.mCtx = ctx;
mUsername = PreferenceManager.getDefaultSharedPreferences(ctx).getString(Preferences.USERNAME, "");
}
public DbAdapter open() throws SQLException
{
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}

get Contex in extended SQLiteOpenHelper class

I have database and i want fill it with some values from xml file.
I'm using this code stream = context.getResources().openRawResource(R.xml.test_entry); to define the stream, but context make error "cannot resolve symbol 'context'".
I tried replace context with getActivity(), getContext(), this, class name and it still doesn't work. I need some help...
public class DatabaseHelper extends SQLiteOpenHelper {
<...>
public DatabaseHelper(Context context) {
super(context, dbName, null, dbv);
}
public void onCreate (SQLiteDatabase db) {
<...>
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+tableName);
onCreate(db);
/////////////////
loadTestValuyes(); <----- My function
/////////////////
}
public void loadTestValuyes() {
test_addEntry stackOverflowXmlParser = new test_addEntry();
List<Entry> entries = null;
InputStream stream = null;
///// I need context here
stream = context.getResources().openRawResource(R.xml.test_entry);
/////////////////
try {
entries = stackOverflowXmlParser.parse(stream);
} finally {
if (stream != null) {
stream.close();
}
}
for (Entry entry : entries) {
<...>
}
}
}
Thanks
You're passing a Context as a constructor argument. Just store it to a member variable:
private Context mContext;
public DatabaseHelper(Context context) {
super(context, dbName, null, dbv);
mContext = context;
and then use mContext where you need a Context.
You can save a reference to the Context object as an instance variable and use it wherever you need it:
public class DatabaseHelper extends SQLiteOpenHelper {
private Context mContext;
public DatabaseHelper(Context context) {
super(context, dbName, null, dbv);
mContext = context;
}
}

android: SQLite Db error

hello i am building a SQLite Db for my android application . this is the code :
package com.example.pap_e;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class FeedsDbAdapter {
private final Context mCtx;
private static final String DEBUG_TAG = "RSSDatabase";
private static final int DB_VERSION = 1;
private static final String DB_NAME = "rss_data";
public static String TABLE = "list";
public static final String ID = "_id";
public static final String RSS = "_rss";
public static final String TITLE = "_title";
public static final String PUBDATE = "_pubdate";
public static final String DESCRIPTION = "_description";
public static final String LINK = "_link";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE_TABLE"+TABLE+"("+ID+ "integer PRIMARY KEY AUTOINCREMENT,"+RSS+"text NOT NULL,"
+TITLE+"text NOT NULL,"+PUBDATE+"text NOT NULL,"+DESCRIPTION+"text NOT NULL,"+LINK+"text NOT NULL"+")");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE);
onCreate(db);}
}
public FeedsDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
public boolean updateAnakoinosi(long rowId, String rss, String title,
String pubdate, String description, String link) {
ContentValues args = new ContentValues();
args.put(RSS, rss);
args.put(TITLE, title);
args.put(PUBDATE, pubdate);
args.put(DESCRIPTION, description);
args.put(LINK, link);
return mDb.update(TABLE, args, ID + "=" + rowId, null) > 0;}
public Cursor fetchAllAnakoinoseis() {
return mDb.query(TABLE, new String[] { ID, RSS, TITLE, PUBDATE,
DESCRIPTION,LINK }, null, null, null, null, null); }
}
The thing is that i get an error at public class FeedsDbAdapter that says:"The blank final field mCtx may not have been initialized" but i had it initialized using private final Context mCtx; Am i missing something here ? Thanks a lot in advance!
You didn't initialize the context yet. You have to initialize it inside FeedsDbAdapter constructor like :
public FeedsDbAdapter (Context context){
mCtx = context;
}
first declare FeedsDbAdapter constructor, because you use FeedsDbAdapter class through its constructor in other classes ans the other activity context will assign to this current context.
Change your code to :
private static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mCtx = context;
}
This question of yours relates to java. This line private final Context mCtx; is just a declaration of field mCtx of type context. And as this field has been declared as final, It has to be iniliazed inside the constructor mCtx = context;. Even if mCtx is not declared as final, it has still to be initialized before being used.
Thats because your class is static... Remove static from your class and change your code to
DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mCtx = context;
}

Sqlite:The constructor is undefined

I have created DBAdapter class which is responsible for making a connection to a Database and does any query and finally close the connection.
I have another class which it is not inherited from Activity class(ReminderBeep), but i have to use my DBAdapter in this class.
Actually i don't know how can i manipulate the DBAdapter constructor to make the connection.*
The error is: The constructor DBAdapter(ReminderBeep) is undefined
DBAdapter is:
public class DBAdapter {
static final String DATABASE_NAME = "MyDB";
static final int DATABASE_VERSION = 2;
final Context context;
DatabaseHelper DBHelper;
SQLiteDatabase db;
public DBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
}
}
//---opens the database---
public DBAdapter open() throws SQLException
{
db = DBHelper.getWritableDatabase();
return this;
}
//---closes the database---
public void close()
{
DBHelper.close();
}
public void insert(String sql)
{
db.execSQL(sql);
}
}
BeepReminder is:
public class ReminderBeep
{
public void DeleteDailyActivities()
{
DBAdapter db=new DBAdapter(this);
db.open();
String sql="delete from DailyWorks";
db.insert(sql);
db.close();
}
}
ReminderBeep is not extendig Activity. But DBAdapter want a Context as paramter,
DBAdapter db=new DBAdapter(this);
this refers to ReminderBeep

Categories

Resources