accessing a DBadapter globally and Finalizing cursor android.database.sqlite ERROR - android

I have a DB that I use in all my activities. There is only one record in the DB.
In the first activity it is opened or created and then put in my globally used object like this
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// first get the current data from the DB
myDBAdapter = new MyDBAdapter(this);
GlobalVars.myDBAdapter = myDBAdapter; // we store the DBAdapter in our global var
myDBAdapter.open();
Cursor cursor = myDBAdapter.fetchMainEntry();
startManagingCursor(cursor);
// if there is no DB yet, lets just create one with default data
if (cursor.getCount() == 0) {
createData();
cursor = myDBAdapter.fetchMainEntry();
startManagingCursor(cursor);
}
Now in another activity I access the already open DB like this...
GlobalVars.myDBAdapter.updateMainEntry(1,.....);
I do not close the DB when leavin one activity to go to the next. The DB is just accessed (since it has been opened at the very first activity).
Only when leaving the app I clode the DB like this...
#Override
protected void onDestroy() {
super.onPause();
myDBAdapter.close();
}
The background why I am also asking this is I get this error...
Finalizing cursor android.database.sqlite.SQLiteCursor#48106730 on
mainEntry that has not been deactivated or closed
and it seems that my app crashes on certain devices - but I can't find the reason for it during debugging.
Is that correct and best practice, or do I have to close the DB when I leave the activity and open it when entering the next activity when switching between activities?
Many thanks!

The best thing (I have it tested in a few apps of mine) is to:
declare database adapter as an activity's instance variable:
private DBAdapter mDb;
create it and open in activity's onCreate():
mDb = new DBAdapter(this);
mDb.open();
close it in activity's onDestroy():
mDb.close();
mDb = null;
Works like charm.
A side note: the Application class onTerminate "will never be called on a production Android device" according to the docs.

You can use sqlite as DB for your application. Then you have to create a common class for your whole application Like " DBAdapter ". Then write codes to manipulate the DB. After that you just have to create DBAdapter's object in your activity. Thus you can access your DB from every activity of your app. http://developer.android.com/guide/topics/data/data-storage.html#db This link can be useful.

Related

Read SQLite table in activity onCreate

In my app I want to initialize some data stored in a SQLite database.
But it turns out the SQLiteOpenHelper onCreate method is not called when I read my database (it is when I write into my database).
My app crash when I read the db for a table that does not exist (it does not crash if I create the table before). I could catch the exception but does not seem very clean to me.
Is it the normal behavior regarding SQLiteOpenHelper onCreate method or am I missing something?
Here is the initialisation function called in activity OnCreate()
private void InitializeDbPlayerList() {
SQLiteDatabase db;
Cursor cursorPlayers;
DbPlayerData dbPlayerData;
db = mGameDbHelper.getReadableDatabase ();
// The following line crash the app if PLAYER_TABLE_NAME does not exist
cursorPlayers=db.query(GameDatabaseOpenHelper.PLAYER_TABLE_NAME,
GameDatabaseOpenHelper.player_columns, null, new String[] {}, null, null,
null);
cursorPlayers.moveToFirst();
for(int j=0;j<cursorPlayers.getCount();j++)
{
dbPlayerData = new DbPlayerData(cursorPlayers.getString(0),cursorPlayers.getFloat(1),cursorPlayers.getFloat(2),
cursorPlayers.getInt(3),cursorPlayers.getInt(4));
mDbPlayerList .add(dbPlayerData);
}
}
Thx
Fabien

When should I close my Database on my Login page?

EDIT
First activity opens a database: I used the code
LoginDbAdapter mDbHelper; // as a data member
called
// in my onCreate() of my main activity login
mDbHelper = new LoginDbAdapter(this);
then in my
public void onResume(){
mDbHelper.open(); // opens only when the activity is resumed
super.onResume();
}
then I do the same thing above in my second activity to add a user. This worked.
My issue is as follows:
**How do i open a link to a second table in my database to access
a users information only. And where do i close it. **
UPDATE
an alternative way that works much better is initializing my DbAdapter in the onResume and then calling DbAdapter.open(); only when i need access to the db and closing it right after the work is done with DbAdapter.close();
note: it is also important to call startManagingCursor(cursor); and stopManagingCursor(cursor);
Might these helps:
find these where you getting writeable permission like these::
SQLiteDatabase db=this.getWritableDatabase();
Now wat you need to do iz::
db.insert(TABLE, null, values);
db.close();//put these after inserting your database;
You need to go in to your DATABASEADAPTER class
then close the database connection after insertion as per above code
in your Activity
mDbHelper= new DatabaseAdapter(this);
and in your insert method of DatabaseAdapter class
SQLiteDatabase db = this.getWritableDatabase();
and at last in your insert method call db.close();
You need to Edit these line inside your LoginDbAdapter inside close() method;
public class LoginDbAdapter
{
// close the database
public void close(){
if(mDbHelper != null){
mDbHelper.close();
mDb.close;//insert these line ;these close sqlitedatabase;
}
}
}
give the command to close inside a try{} catch{}

How to Open/Close SQLite db in Android Properly

I have an app that functions properly and does not force close or crash. But when I look at LogCat, it occasionally gives me this:
05-20 15:24:55.338: E/SQLiteDatabase(12707): close() was never explicitly called on database '/data/data/com.---.--/databases/debt.db'
05-20 15:24:55.338: E/SQLiteDatabase(12707): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
a little ways down...
05-20 15:24:55.338: E/System(12707): Uncaught exception thrown by finalizer
05-20 15:24:55.338: E/System(12707): java.lang.IllegalStateException: Don't have database lock!
I am not sure when I should be opening and closing my Database?
I have a Main activity that is simply a splash screen. It then goes into an activity that calls a ListView using info from the DB; so it is at this activity where the DB is first opened.
There is also one other Activity where the DB is required that branches off the one with the ListVeew. When am I supposed to be opening and closing this? Word seems to be that I simply need to open once, and then close when the app is "paused", "stopped" or "destroyed".
If this is the case, where do I put the db.close() method... in the Splash Screen Main Activity where onStop, etc is located? or the same Activity as the one that opens the DB? or.. is there another place?
UPDATE:
This is the line in code that the error keeps pointing to:
public void open() throws SQLException {
database = dbHelper.getWritableDatabase();
}
If you're using an instance of a DatabaseHelper class, and after you initialize the DBHelper object, every time you do work in the database you should call the open method before you do work, then create a new cursor, query the database, do work with the information you just stored in the cursor, when you're done close the cursor, then close the database. For example if you wanted to grab every item in a database you would do something like :
...
DataBaseHelper db = new DataBaseHelper(this);
...
db.open();
Cursor cursor = db.getAllItems();
maxCount = cursor.getCount();
Random gen = new Random();
row = gen.nextInt(maxCount); // Generate random between 0 and max
if (cursor.moveToPosition(row)) {
String myString = cursor.getString(1); //here I want the second column
displayString(myString); //private method
}
cursor.close();
db.close();
getAllItems is a public method in my DatabaseHelper, it looks like this in case you were wondering
public Cursor getAllItems() {
return db.query(DATABASE_TABLE,
new String[] {
KEY_ROWID,
KEY_NAME
},
null,
null,
null,
null,
null);
}
This is how I access my database and I haven't gotten any of the errors you've got, and it works perfectly.
I used to do the way #Shikima mentioned above but in complex applications which has many background services, multi-threading,etc it can get real tiresome when you have to manage many database instances and on top of that, opening and closing them.
To overcome this, I used the following method and it seems to be working fine.
1.
Declare and initialize an instance of YourDBHelperClass in your Application base class like this :
public class App extends Application {
public static YourDBHelperClass db;
#Override
public void onCreate() {
super.onCreate();
db = new YourDBHelperClass(getApplicationContext());
db.open();
}
}
2.
In you activity, or any other place you want to use the DB, initialize the YourDBHelperClass object like this :
YourDBHelperClass db = App.db;
And then you can use the database anyway you want without having to worry about opening and closing it manually each time. The SQLiteOpenHelper takes care of the closing when the Application is destroyed
You are probably not handling your database correctly; you are opening more database instances than you are closing.
There are a number of design patterns you can follow to correct this behavior. You might want to consult this answer for more information.

Refresh/Reload database reference in custom ContentProvider after restore

I use a ContentProvider in my app and everything works great except for one little issue. I have a backup and restore function that backs up the database to a file on the SD card and then those backup files can be restored to overwrite the current database. This whole process is working, but the ContentProvider still holds the reference/cache to the original database once one of the old backup files is restored. I can't seem to find a way to refresh or reload the database reference in the ContentProvider. I know the restore works because I can see the records in the db with SQLite Editor and when I close and re-open the app, it displays the correct records.
Does anybody know a way to do this? Is there a way to close and re-open the ContentProvider that I'm not seeing?
If you are targeting >= API 5 you can get a reference to your ContentProvider via a ContentProviderClient, and run a method specific to your implementation:
ContentResolver resolver = context.getContentResolver();
ContentProviderClient client = resolver.acquireContentProviderClient("myAuthority");
MyContentProvider provider = (MyContentProvider) client.getLocalContentProvider();
provider.resetDatabase();
client.release();
Add the reset method to your ContentProvider implementation:
public void resetDatabase() {
mDatabaseHelper.close();
mDatabaseHelper = new MyDatabaseOpenHelper(context);
}
Are you maintaining a reference to the actual SQLiteDatabase in your content provider (something like calling SQLiteOpenHelper.getWritableDatabase() in onCreate() and then keeping that reference)? Or do you get the DB object from someplace like a helper in each provider method?
Typically, if you only keep a local reference to the helper and get the writable/readable database instance inside of each method as needed then this problem should go away. If not, perhaps we can take a look at the provider code?
Hope that Helps!
Here is my solution.
public class DataProvider extends ContentProvider {
private DataDbHelper dbHelper;
#Override
public boolean onCreate() {
// nothing here
return true;
}
private DataDbHelper getDbHelper() {
if (dbHelper== null) {
// initialize
dbHelper = new DataDbHelper(getContext());
} else if (dbHelper.getReadableDatabase().getVersion() != DataDbHelper.VERSION) {
// reset
dbHelper.close();
dbHelper = new DataDbHelper(getContext());
}
return this.mOpenHelper;
}
}
query(), insert(), update(), delete() use getDbHelper() to obtain an SQLiteDatabase
The full code of my Android app is available here if you need more info.
You can also simply use the delete method without a selection:
context.getContentResolver().delete(YourProvider.CONTENT_URI, null, null);

Managing database connections in an Android Activity

I have an application with a ListActivity that uses a CursorAdapter as its adapter. The ListActivity opens the database and does the querying for the CursorAdapter, which is all well and good, but I am having issues with figuring out when to close both the Cursor and the SQLiteDatabase.
The way things are handled right now, if the user finishes the activity, I close the database and the cursor. However, this still ends up with the DalvikVM warning me that I've left a database open - for example, if the user hits the "home" button (leaving the activity in the task's stack), rather than the "back" button.
If I close them during pause and then re-query during resume, then I don't get any errors, but then a user cannot return to the list without it requerying (and thus losing the user's place in the list). By this I mean, the user can click on any item in the list and open a new activity based on it, but will often want to hit "back" afterwards and return to the same place on the list. If I requery, then I cannot return the user back to the correct spot.
What is the proper way to handle this issue? I want the list to remain scrolled properly, but I don't want the VM to keep complaining about unclosed databases.
Edit: Here's a general outline of how I handle the code at the moment:
public class MyListActivity extends ListActivity {
private Cursor mCursor;
private CursorAdapter mAdapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new MyCursorAdapter(this);
setListAdapter(mAdapter);
}
protected void onPause() {
super.onPause();
if (isFinishing()) {
mCursor.close();
}
}
protected void onDestroy() {
super.onDestroy();
mCursor.close();
}
private void updateQuery() {
// If we had a cursor open before, close it.
if (mCursor != null) {
mCursor.close();
}
MyDbHelper dbHelper = new MyDbHelper(this);
SQLiteDatabase db = dbHelper.getReadableDatabase();
mCursor = db.query(...);
mAdapter.changeCursor(mCursor);
db.close();
}
}
updateQuery() can be called multiple times because the user can filter the results via menu items (I left this part out of the code, as the problem still occurs even if the user does no filtering).
Again, the issue is that when I hit home I get leak errors. Yet, after going home, I can go back to the app and find my list again - cursor fully intact.
I usually have one SQLiteOpenHelper per app:
public class MyApp extends Application {
private static MyDbHelper dbHelper;
#Override
public void onCreate() {
super.onCreate();
dbHelper = new MyDbHelper(this);
}
#Override
public void onTerminate() {
super.onTerminate();
dbHelper.close();
}
public static SQLiteDatabase getDB() {
return dbHelper.getWritableDatabase();
}
}
Haven't had any problems with this approach so far.
And you can use startManagingCursor(..) available in Activity subclasses (though I let Adapters manage Cursors):
public class SomeAdapter extends CursorAdapter {
public void setNewFilter(CharSequense query){
// in fact, I use a DAO here
Cursor c = MyApp.getDB().query(..);
changeCursor(c);
}
}
I'd disagree. Looking at the android docs, specifcally this image http://developer.android.com/images/activity_lifecycle.png I would say the resource should be created in the onstart() method and cleaned up in the onstop() method. This is how google handles it in their code, google analytics docs for android
I would suggest using a Abstract Factory method to ensure that your SQLiteDatabase remains a singleton. Check out my blog post on the topic:
Correctly Managing Your SQLite Database
Close the Cursor and SQLiteDatabase in onDestroy(), for those things not already closed, and see if that helps. There may be scenarios where isFinishing() is false in onPause(), yet onDestroy() still winds up being called.
yeah usually
onDestroy()
is the where you should be closing your DB and open up it in the
onCreate()

Categories

Resources