I've got custom adapter class, which incapsulates SQLiteDatabase. Adapter manages db connection:
public AutoDBAdapter(final Context context){
this.context=context;
checkDatabase();
try{
openDB();
}catch(Exception e){
e.printStackTrace();
}
checkDatabase()
method checks if DB exists and copies it from assets if necessary.
private void openDB() throws SQLException{
if(db==null)
db=SQLiteDatabase.openDatabase(dbFileName, null, SQLiteDatabase.OPEN_READWRITE);
}
I create AutoDBAdapter class inside my Activities.
I used this approach because I need my DB to be accessible from multiple activities. I know that that's not a good to do it.
My question: when should I close DB connection?
Any suggestions would be useful. Thanks.
If the db isn't used that often you should close it after each operation. If you are going to use it alot and want to keep it open, you should close it in the onPause method of the Activity.
Related
I don't know how to handle this correctly without getting database locked errors.
My app basically downloads many items in batches of 100 rows (~ 60.000 items) and inserts them in the database. Each batch of 100 rows is processed into a transaction.
The main activity allows the user to navigate between screens (fragments) while records are being downloaded and inserted. Most of the other screens contains read data from the database. I get a lot of database lock errors during reading. All readings are done in the main activity (not fragments) in different async tasks
So far I just used the "classic approach"
public class DBAdapter {
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) {
db.execSQL(DB_CREATE_TABLES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Utils.log("Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
onCreate(db);
}
public DBAdapter open() throws SQLException {
database = DBHelper.getWritableDatabase();
return this;
}
public void close() {
DBHelper.close();
}
Then on my activity's onCreate() I call db = new DBAdapter(context); and each time I am doing an database operation (read/write) I call db.open() and after the insert/read is done I call db.close()
My questions are:
what would be the best approach to this situation ?
Considering I do a lot of write/read would it be better to call db.open on onCreate and db.close() on onDestroy() ? Would this be better than calling open/close each time I need to access the database ?
What do I need to do to avoid database locking on reading ?
I had a exactly similar situation like yours. In addition to what you described, in my app the user also can update the database through input on the screen.
The way I resolved it ( I don't know if it's the best way, but I hardly see any locking issue now)
Make a singleton class derived from SQLiteOpenHelper to make sure only one instance is running at any given time.
Implement ContentProvider class for insert/update/delete/query operations. Make all those functions 'synchronized'
Only close the db in ContentProvider's shutdown function. I do a very frequent db operations, so I don't want to open/close everytime. But I am not sure if it's the correct way of handling it.
Do access DB only through ContentProvider interface from anywhere
A very simple approach, or maybe a workaround is using synchronized methods for opening and closing the database object. I don't really know if it's the best practice, but at least it's simple and easy. Add this methods to your DBAdapter Class, and use them instead of db.open and db.close. The use_count attribute simple holds how many times open has been called. Initialize it with a value of 0. Also, in order to make it work on your solution be sure to pass the same DBAdapter object between the fragments. Don't create a new one everytime :
private int use_count = 0;
public synchronized void doOpen()
{
use_count++;
this.open();
}
public synchronized void doClose()
{
use_count--;
if (use_count == 0)
{
this.close();
}
}
Consider wrapping the SQLite database in a ContentProvider and using CursorLoader to do the queries from the various activities & fragments. This isolates the management of the database from the Activity/Fragment life cycle and can result in many fewer open/close cycles.
You may still run into contention between the reads and writes, but having all the database interaction in the same module should make it easier for you to address these issues.
Some interesting links: http://www.vogella.com/articles/AndroidSQLite/article.html#todo
When to use a Content Provider
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{}
I'm getting two contradicting Exceptions when creating and populating my new SQLiteDatabase in Android. In short my code:
SQLiteOpenHelper extending class:
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_TABLE_CREATE);
loadLevelData(db); //puts data in the database
//db.close(); <<< ?
}
In my activity class I instantiate this class (in onCreate()), and call getWritableDatabase():
dbHelper = new DbOpenHelper(getApplicationContext());
database = dbHelper.getWritableDatabase();
Now if I don't call db.close() after populating the database, like above, I get
android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
However if I DO close it, I get the following exception:
java.lang.IllegalStateException: database not open
on getWritableDatabase().
This really confuses me, so could anyone help me with what's wrong?
You are not expected to close the database in the DatabaseHelper class. However you need to close it every time you open it calling getWritableDatabase:
dbHelper = new DbOpenHelper(getApplicationContext());
database = dbHelper.getWritableDatabase();
//... do something with database
database.close();
You are closing your database at the wrong time.
I typically keep the database around like this:
public class MyActivity extends Activity {
SQLiteDatabase writeableDb;
// ...
// Code
// ...
public void onStart(){
super.onCreate(savedState);
// Do stuff, get your helper, etc
writeableDb = helper.getWriteableDatabase();
}
public void onStop(){
writeableDb.close();
super.onStop();
}
}
Alternatively, wrap all your code working with that db connection in a try/finally block
db = helper.getWriteableDatabase();
try { // ... do stuff ... }
finally { db.close(); }
Note: All of the opening/closing should be done in the Activity working with the database, not the open helper.
I have been learning (slowly but surely) how to do deal with sqlite databases on android systems. Using information I found here:
http://mfarhan133.wordpress.com/2010/10/24/database-crud-tutorial-for-android/
I have learned how to create, load things into and retrieve information from a database on my android system. One of the hitches was this method here:
public Cursor getClientsCursor() {
StudioTabOpenHelper dbAdapter=StudioTabOpenHelper.getDBAdapterInstance(this.getListView().getContext());
try {
dbAdapter.createDatabase();
} catch (IOException e) {
Log.i("*** select ",e.getMessage());
}
dbAdapter.openDataBase();
String query="SELECT * FROM CLIENTS;";
Cursor c = dbAdapter.selectRecordsFromDB(query, null);
//dbAdapter.close();
return c;
}
The problem was that the above code was closing the adapter I had opened...this was causing the part where I used that returned cursor to complain that database conn#0 already closed. So I commented out that dbAdapter.close(); I think this is bad in the future if i call this method again.
So my question is: Should I at the start of my application create the dbAdapter and open the database and leave it open and never close it? (how do i pass the dbAdapter around to activities, fragments etc if I go this route) ... or how can I use the getClientsCursor method as is and figure out some other way to pass back the cursor and be able to call the .close()?
/**
* Open the database
* #throws SQLException
*/
public void openDataBase() throws SQLException {
String myPath = DB_PATH + DATABASE_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
/**
* Close the database if exist
*/
#Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
My adapter code was gotten from here:
http://mfarhan133.wordpress.com/2010/10/24/database-crud-tutorial-for-android/
I just didn't call my class DBAdapter but called it StudioTabOpenHelper.
You may close your adapter on the
onDestroy() method of your activity.
Hi I am new to android and I have a problem in creating a database.
public class database extends ListActivity {
/** Called when the activity is first created. */
private final String MY_DATABASE_NAME = "myCoolUserDB.db";
private final String MY_DATABASE_TABLE = "t_Users";
Context c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> results = new ArrayList<String>();
setContentView(R.layout.main);
SQLiteDatabase mydb=null;
try
{
mydb.openOrCreateDatabase(MY_DATABASE_NAME, null);
} catch(Exception e){}
}
}
When I run this code it throws a run time exception. Please help me.
If you are going to call a static method like openOrCreateDatabase, do it on the class (SQLiteDatabase.openOrCreateDatabase(...)), not an instance. It's a lot clearer - the way you've done it looks like you're calling an instance method, so looks like a sure NullPointerException, which of course is misleading.
As someone else has stated, the stack trace would be the most useful thing when asking for help with an exception.
(Almost) never catch an exception without at the very least logging it. Don't just do nothing with it. There are of course exceptions to every rule, but let's not go there for the moment. Anyway, if you don't at least log it, you're just throwing away information that would tell you what went wrong when everything goes to crap later.
You shouldn't be using that method directly, and should instead be extending SQLiteOpenHelper . See the android developers page on data storage to get started (I'd post a link but apparently I'm only allowed one link in my post ?!), and since you've probably had to download the SDK to get going, look in the samples that come with it for the Notepad sample application. That contains a NotePadProvider class, which is a good example of both a content provider and database access, which often go hand-in-hand on android. I'd suggest compiling that application and making some simple changes to it before you jump into making your own one.
For working with sqlite database you need to create class extended from SQLiteOpenHelper:
private class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(UPGRADE_TABLES);
}
}
Then you can get access to db using DbHelper object:
DBHelper dbHelper = new DBHelper(Activity.this);
SQLiteDatabase db = dbHelper.getReadableDatabase();
I run into the same problem. It figures out that two bugs happens during development
dir "databases" was not existent
accendently ".db" was created as directory.
They following code cover both
File dbFile = getDatabasePath ("abc.db");
if (dbFile.isDirectory ()) {
dbFile.delete();
}
if (! dbFile.exists()) {
String path = dbFile.getParent ();
new File (path).mkdirs ();
}
database = SQLiteDatabase.openDatabase (dbFile.getAbsolutePath (), this, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY);
Hope this helps
I think SQLiteOpenHelper is only useful for "single table" databases. For multiple table applications I consider directly using SQLiteDatabase fit better to a good architecture.
This is a simple post which tells you how to insert data in to a SQLite database in Android and further more this links shows you how to retrieve data from a SQLite database in Android .