Async tasks and Sqlite - android

I have a service that runs when device is connected to the internet. It fetches data from sqlite which is then uploaded on the server. A listfragment has been populated with the data from the database.
Since I have service, I am getting errors like "database already closed" "database not opened".
My dbHelper object is static.
I am calling SQLiteDatabase db = this.getWritableDatabase(); at the start of each method that will acess the database. And db.close() at the end of each method.
Should I close the db.close() only in onDestroy()? ... Would this solve the issue or is there another way?

first of all, if you ever want to close a database, you have to check if it is isOpen().
Now, in general your SQLiteOpenHelper implementation sould be a singleton and override the close() method to be:
#Override
public synchronized void close() {
mOpenConnections--;
if (mOpenConnections == 0) {
super.close();
}
}
where mOpenConnections is a member that holds the number of connections made through the SQLiteOpenHelper. this member should be incremented everytime somebody opens the database.
#Override
public synchronized void onOpen(SQLiteDatabase db) {
super.onOpen(db);
// increment the number of users of the database connection.
mOpenConnections++;
}
then when you need to close a database use SQLiteOpenHelper.close() method.
This should solve all your problems.

The only solution that I have found to work reliably across multiple activities is to call getWritableDatabase in the onCreate method of every activity.
As has been pointed out, any service should have its own SQLiteOpenHelper instance. I think this happens anyway, because the service runs in a separate address space, but it is best to make sure.

Related

What is the best practice when closing SQLiteDatabase in Android?

In official docs, you read:
public SQLiteDatabase getWritableDatabase ()
...
Once opened successfully, the database is cached, so you can call this method every time you need to write to the database. (Make sure to call close() when you no longer need the database.)
As for the SQLiteOpenHelper, I implemented a singleton pattern for the only instance, but how about the SQLiteDatabase?
How effective is the cache?
Android SQLite DB When to Close
I looked at this post, but there is no discussion over caching.
Open and close your db before and after each operation, respectively.
Never leave it open, when not needed.
Your mantra should be: open it, use it, close it.
Repeat for every db operation.
Same goes for Cursors as well.
I always close my SQLiteDatabase after every query. For example, here's how I implement my insert methods:
public void insert(ContentValues valuesMap){
SQLiteDatabase db = getWriteableDatabase();
try{
db.insert("ContactsTable", null, valuesMap);
}catch(Exception e){
// do someting...
}finally{
db.close()
}
}

SQLiteDatabase and Cursor leaks and close() calls

I need some help on database and cursor managing. I noticed that, when entering /leaving certain fragments, I get:
W/SQLiteConnectionPool﹕ A SQLiteConnection object for database '+data+data+database' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.
That made me go back from scratch and check what I'm doing and when. I have:
a DatabaseHelper class extending SQLiteOpenHelper, with just some methods for creating and updating the db;
a DatabaseManager class, extending nothing. I use this, among other things, to keep a single reference to a DatabaseHelper object:
public class DatabaseManager {
private DatabaseHelper h; //class extending SQLiteOpenHelper
public DatabaseManager(Context c) {
if (h==null) {
h = new DatabaseHelper(c.getApplicationContext()); }
public Cursor query(...) {
SQLiteDatabase db = h.getReadableDatabase();
return db.rawQuery(...)
}
public void closeConnection() {
SQLiteDatabase db = h.getWritableDatabase();
db.close();
h.close();
}
}
in this class, some methods querying the database and returning a Cursor object;
in this class, a closeConnection() method, which I'm not really sure of.
I use this class from fragments, calling each time new DatabaseManager(getActivity()). This should not create a new helper reference. Right now I am:
calling Cursor.close() as soon as I got the information I wanted from the query;
never calling open() on my helper neither on my SQLiteDatabase, although I read somewhere that should be done. When exactly? Why it all works even without calling it?
calling manager.closeConnection() in the onStop() method of fragments that make use of my database. As you can see, that calls close on h (a reference to the helper class) and on a readable SQLiteDatabase object. However, I'm not really sure about that, because it closes the helper reference h without making it null, so maybe there are some problems with future calls to new DatabaseManager() ? Maybe dealing with database with a singleton pattern does not require you to call h.close()?
Apart from that, needless to say (that's why I'm asking), when switching through fragments I get the above mentioned warning. What's wrong? What should I do? What does end transactions in progress mean? Should I modify my closeConnection() method, call it in different lifecycle times, or don't call it at all?
After embarrassing issue pointed out by #Selvin, I made h static. Now if I remove any call to closeConnection(), it all works well and I don't get any warnings. That means I'm never calling neither h.close() or db.close(). Is that ok? If not, when should I call it?

Android SQlite multithread access

I am using SQLiteOpenHelper to write and read from SQlite database on Android. When user clicks on UI I read from SQLite database using AsyncTask but at the exact samo moment I am updating and writing to the database in the background using other AsyncTask.
Every x times I get database locked exception. How can I fix this? Can SQlite be accessed somehow from multiple thread at the same time?
I am using it like that: I have a Database class which extends from SQLiteOpenHelper. I implemented onCreate and onUpgrade methods and everytime I am reading from database or writing to database I use SQLiteDatabase like that:
SQLiteDatabase database = null;
try {
database = new Database(context).getWritableDatabase();
....
writing and reading from database...
....
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
At the end I also close SQLiteStatements and Cursors if I use them. Should I use #Justin answer and have a singleton of database class in Application?
This is the error I get:
E/SqliteDatabaseCpp(17377): sqlite3_open_v2("/data/data/com.skulptur/databases/LGM.s3db", &handle, 6, NULL) failed
E/SQLiteDatabase(17377): Failed to open the database. closing it.
E/SQLiteDatabase(17377): android.database.sqlite.SQLiteDatabaseLockedException: database is locked
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:983)
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:956)
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1021)
E/SQLiteDatabase(17377): at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:750)
E/SQLiteDatabase(17377): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:149)
E/SQLiteDatabase(17377): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:223)
This is what I do to avoid locking issues.. I let my application handle a single instance of my db helper and always refer to it to get a handle on my DB.
public class MyApp extends Application {
// My instance of SQLiteOpenHelper
public static DbHelper openHelper;
#Override
public void onCreate() {
super.onCreate();
if (openHelper == null) {
openHelper = new DbHelper(this);
}
}
public synchronized static SQLiteDatabase getDB() {
return openHelper.getWritableDatabase();
}
}
Once you do this, anytime you want to do a db query, get the db handle like MyApp.getDB() and you will never have a locking issue. Be sure to NEVER close the DB though. This pattern maintains a single connection at all times in your app. SQLite is meant to be synchronous on Android so if you have long running DB processes, like a 1000 inserts in a single transaction you'll want to code it like this:
db.beginTransaction();
try {
for (DBRow row : insertList) {
// your insert code
insertRow(row);
db.yieldIfContendedSafely();
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
This will allow other queries to interject themselves so that you won't see your app grind to a halt during background updates.
Implement a ContentProvider on top of the Database with Loaders it will handle the threading.
You can consult this tutorial: http://www.vogella.com/articles/AndroidSQLite/article.html
There are few things to try.
First try passing the same instance of SQLiteOpenHelper to every of your tasks.
Second is using beginTransaction and endTransaction on your SQLiteDatabase inside of your Helper.
Third is adding synchronized to every of your helper methonds being used in tasks.
I think you are using database connections incorrectly. It can be caused by unclosed cursors or smth else. Sqlite database implementation is thread safe and can be accessed simultaneousely from different threads.
Please provide more details about your problem (exception stack trace, code sample that causes exception etc) in order we can help you.

sqlite access from multiple threads for reading

there are similar questions but not clear answer around using sqlite db from multiple threads.
Consider the following scenario:
class MainActivity extends Activity {
DbHelper db; //extends sqliteopenhelper
...
void M1() {
db.getReadableDatabase();
Cursor c = db.query("...."
...
db.close();
}
void M1() {
db.getReadableDatabase();
Cursor c = db.query("...."
...
db.close();
}
ok, this is not multi-thread but question is that,
does it become a problem to use the same instance of sqliteopenhelper instance (i.e. db) like above, opening and closing in many times in different methods?
And my scenario is the following:
myAsync extends AsyncTask
doInBackground(.. {
do something using M1(); //this is a background thread
}}
onResume()...{
myAsync.execute();
M2(); //this is the main thread
...
}
if you see that in the async scenario, it is probably that two method can access the same database at the same time(for reading only- how about writing?). But they are using the same instance of SqliteOpenHelper. Would it cause to collision and if so how to avoid this?
I would like to learn more about sqlite database and concurrency
Any ideas would be greatfully appreciated.
ya there is a chance of not collision but your db may close when another thread is aquired, you can go for "Synchronized" concept of thread ie priority and etc when we use synchronized keyword then, one thread completes it task then other thread will starts

How careful should I be with thread-safety when creating methods/activities which interact with SQLite database?

I am creating an app which allows for many different Activities to be started from a TabActivity(up to ~25). Most of the activities require data from the sqlite database, so when onCreate is run, an AsyncTask creates an SQLiteOpenHelper object(which will open a readable/writable database), runs a query, data is retrieved, and everything is then closed.
i was just testing messing around to see if i could break something, so i added every Activityto the TabActivity's TabHost. I then started mashing each tab as quickly as possible.
i noticed that very quickly i began to see in the LogCat: Caused by: android.database.sqlite.SQLiteException: database is locked: BEGIN EXCLUSIVE; and the app proceeded to die.
Typically there will only be about 4-6 tabs(i can just limit the user anyway) for the TabHost. I haven't been able to break anything with a small amount of tabs to mash, but i am still worried that maybe i am accessing the database in a poor way.
How can i prevent my SQLiteDatabase objects to cause a lock?
If i create a ContentProvider will that eliminate the possibility of database locking?
Do you have any suggestions for changes I could make for accessing data from an SQLiteDatabase?
I ended up taking the approach of using the Application class and storing 1 SQLiteOpenHelper and trying my best to keep it synchronized. This seems to be working great - i put all my 25 activities in the TabHost and mashed away on them with no errors.
I am calling ((SQLiteDbApplication)getApplication()).setDbHelper(new DBHelper(this, Constants.DB_NAME, null, Constants.DB_VERSION_CODE)); method(shown below) in every onCreate() in my activities
Any further suggestions to this approach or to the changes i made using this Application class?
import android.app.Application;
import android.database.sqlite.SQLiteDatabase;
public class SQLiteDbApplication extends Application {
private DBHelper dbHelper;
private SQLiteDatabase db;
public synchronized DBHelper getDbHelper() {
db = dbHelper.getDatabase();//returns the already opened database object
while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads());
return dbHelper;
}
public synchronized void closeDb() {
if(null != dbHelper)
dbHelper.close();
if(null != db)
db.close();
}
#Override
protected void finalize() throws Throwable {
if(null != dbHelper)
dbHelper.close();
if(null != db)
db.close();
super.finalize();
}
public synchronized void setDbHelper(DBHelper dbHelper) {
if(null == this.dbHelper) {
this.dbHelper = dbHelper;
this.dbHelper.setDb(this.dbHelper.getWritableDatabase());//creates and sets the database object via getWritableDatabase()
}
}
}
If you are to worried about all the database connections try to limit yourself to one SqliteOpenHelper and be sure to wrap a synchronization layer around it.
You can extend the application class and then call getApplication and cast the object you get into your application. Now you can store a SqliteOpenHelper in this application class and build your own thread safe access method to the database connection.
If you are using AsyncTask in all of your onCreate methods and you are experiencing problems with a lot of tabs these problems can also occur with a slower device, a faster user or a database that is grown big over the time of usage.
Depending on the use case of you app you can go the save way and go through all the effort and pain of threading and locking, or you can just publish the app with a number of tabs that never produced the error and be sure to catch the database exception and send yourself a notification (for example through google analytics) to test if the threading problem does occur in real life usage of the app.
All activity callbacks happen on the main thread, so in the scenario you describe there is no multi-threading going on, no matter how many activities or tabs you have.
ContentProvider doesn't provide any locking. In fact, it can introduce multithreading where you wouldn't already have it because it allows other processes to make calls in to your own process, and when that happens the call is dispatched from a separate thread in your process (not on the main UI thread).
Of course if you create your own threads, then you will also have multi-threading going on.

Categories

Resources