-1

As a new Android programmer, I followed various online examples to create my own class that extends SQLiteOpenHelper...

public class MySQLiteHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION=1;
private static final String DATABASE_NAME="MyDB";

// Main Database Operations
public MySQLiteHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_TABLE_A);
    db.execSQL(CREATE_TABLE_B);
}

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
...

public long addRecord(){
    SQLiteDatabase db = this.getWritableDatabase();
....

etc

This works throughout my various activities with no issues. When I want to use it, I call...

    MySQLiteHelper db = new MySQLiteHelper(this);

Then I call the various routines like...

db.addRecord();

Now I have created a secondary class that I need to use throughout the application. In that class, there are some routines that need to process data from the database. Problem is, I can't declare the MySQLiteHelper because of the this which errors out.

Doing some online search I think I understand that I need to get the Context from the application (or the calling activity??), but not sure how to go about doing that with this code.

As I mentioned, I am new to Android... so any code examples would be greatly appreciated.

EDIT

I need to clarify this secondary class as mentioned above. From the aforementioned online examples, the second class is used to "hold" the database record information. It looks something like this...

public class Acct {
    private int     _id;
    private String  _name;
    private String  _phone;

    public Acct() {
    }

    public int get_id(){
        return this._id;
    }
    public void set_id(int id) {
        this._id=id;
    }

    public void set_name(String name){
        this._name=name;
    }
    public String get_name(){
        return this._name;
    }

    public void set_phone(String phone){
        this._name=phone;
    }
    public String get_phone(){
        return this._phone;
    }
    ...

This is typically used with something like this in an activity...

MySQLiteHelper db = new MySQLiteHelper(this);
Acct acct = new Acct();
acct=db.getAccount(searchId);
myEditText.setText(acct.get_name());
...

Where my problem arises, I want to create a routine and code it IN the Acct class so it can be referenced such as...

acct.UpdateData();

This UpdateData routine is where we need to access the db and thus the MySQLiteHelper. It needs to be able, for each account, to go into the database, access some information from another table, do some processing, and store a summary back into this table for easier reference. As mentioned, there is no Context in the Acct class, so this is where I am getting confused.

And to make matters worse, because the Acct class is a 'holding' place for data from the DB, the online examples also use Acct IN the 'MySQLiteHelper' itself during the getAccount routine....

public Acct getAccount(int id){
    SQLiteDatabase db = this.getReadableDatabase();

    String SQL_STRING="SELECT * FROM "+ACCT_TABLE+" WHERE "+ACCT_FLD_ID+" = "+String.valueOf(id);
    Cursor cursor =
            db.rawQuery(SQL_STRING, null);

    Acct acct = new Acct();

    if (cursor!=null) {
        cursor.moveToFirst();

        acct.set_id(cursor.getInt((cursor.getColumnIndex(ACCT_FLD_ID))));

        acct.set_name(cursor.getString(cursor.getColumnIndex(ACCT_FLD_NAME)));
        acct.set_phone(cursor.getString(cursor.getColumnIndex(ACCT_FLD_PHONE)));
                    cursor.close();
    } else {
        acct = null;
    }
    db.close();
    return acct;
}

I hope all this additional helped clarify what I am trying to do for the couple comments and answers posted so far. If you need more information, please ask. I'd like to get this to work, just still not sure how.

Peter
  • 427
  • 4
  • 14
  • 1
    Instead of giving code of your `SQLiteOpenHelper` it would be more useful if you showed at least skeleton code of your 'secondary' class and examples of how it is actually instantiated and used. Yes, you need to have an instance of a `Context` but where you get that from and when you get it may vary depending on usage. – Squonk Nov 07 '15 at 03:57

2 Answers2

1

Your problem is you need a Context to call the constructor of MySQLiteHelper. You've been successful doing so in an Activity (which is a Context), but now you have some other class (which I will call "Foo") that isn't a Context and doesn't have one.

A quick solution is to make Foo take a Context in its constructor, and instantiate your MySQLiteHelper like so:

public class Foo {
    private MyOpenHelper openHelper;

    public Foo(Context context) {
        openHelper = new MyOpenHelper(context.getApplicationContext());
    }
}

If Foo is a singleton, you can do the same thing in whatever method obtains the instance (i.e. force the caller to provide a Context). Every application component either is a Context (Activity, Service) or has a Context (BroadcastReceiver gets one in onReceive(), ContentProvider has getContext()).

The use of getApplicationContext() here is worth noting: The Application object for your app is always a singleton--only one instance of it will exist for as long as your app is running (this is guaranteed by the OS). Activities can be destroyed, and creating a MySQLiteHelper with one can cause a memory leak. The application Context always exists and so it cannot be leaked.

Karakuri
  • 38,365
  • 12
  • 84
  • 104
  • I added more information to my original question. I also tried your example in my `Foo` called Acct. If I understand your comment, then when I initialize Acct `Acct acct=new Acct()` outside of the Acct class itself, I need to pass the activities THIS...Correct? If so, what do I do when I need Acct in `MySQLiteHelper` class itself (as mentioned in my edit) which doesn't have a Context either? – Peter Nov 08 '15 at 01:07
  • @Peter You can make the `updateAccount()` method take a `MySQLiteHelper` as an argument. Or, you can make the `updateAccount()` method in `MySQLiteHelper` instead and give it the `Acct` that needs to be updated. There are probably other options as well, it depends how you want to structure your code. – Karakuri Nov 08 '15 at 05:35
  • Can you "store" the application context in a global type variable and use it throughout an application? Would that work? – Peter Nov 08 '15 at 22:52
  • You can extend the `Application` class and declare in your manifest to use that class when Android runs your app. Inside of that class you could have a public static method that simply returns `this`, so you can call it from anywhere. – Karakuri Nov 09 '15 at 04:12
  • @Peter (and Karakuri) - just for reference WRT the `Application Context` please see https://possiblemobile.com/2013/06/context/ - there are different types of `Context` and using the correct type in the correct place is important to take note. On the whole, the `Application Context` will be OK with `SQLiteOpenHelper` but it is a partial `Context` and can't do everything in other scenarios. – Squonk Nov 09 '15 at 20:58
  • Thanks @Squonk... interesting article, explains alot. – Peter Nov 10 '15 at 01:06
0

Instead of using this, Try to use MainActivity.this or getApplicationContext().

Hope this help!

xxx
  • 3,315
  • 5
  • 21
  • 40
  • As `this` refers to an actual instance of a Java class, using `MainActivity.this` would only be valid if there is a current instance of `MainActivity` and would normally be used by by an inner class of `MainActivity` or by overriden methods of inline / anonymous classes / interfaces. The `getApplicationContext()` method is actually a method of `Context` and its subclasses so basically any class able to call `getApplicationContext` must already *BE* a `Context` which defeats the object of doing so. – Squonk Nov 07 '15 at 04:17
  • @David H Ng... I tried both this as well as MainActivity.this... that didn't work. – Peter Nov 08 '15 at 01:08