I'm writing an application with an "online mode", that is, data is downloaded, parsed and inserted into a SQLite database as needed. All this is performed by a service. The app consists of several activities that ask the service for a data update (different data depending on the activity).
When the user navigates through the activities (without waiting for the service to finish), it's very easy to get SQLiteExceptions (message: database is locked).
I thought about using synchronized blocks, but that would force the user to wait while loading a new activity (that needs database access to load) while the service finishes updating. So that seems a dead end.
Another option might be to stop the update when in the onStop method of each activity. Of course, the update will be interrupted, but that's not a big issue. Problem with this is that I'm not sure how to approach it.
My question is, how can/should I handle this?
If your activity is only going to read and not write to database like my case, this is what i did as a workaround:
create a service ( i.e DatabaseService 0 and use it as a central point to access database (i.e open a database connection) to ensure you only have one dbhelper at a time.
all activity and service which need to access database have to establish a connection to DatabaseService
ensure that only your DownloadService's thread is able to write to database and it should use transaction
after that, you can use getReadable database to read / use the connection to stop the download service , etc.
Just make sure that you only use 1 dbhelper.
Related
I am working on a chat application and in chat we are getting lots of update from server. And we are also saving the updates into the local SQLite database file.
Can someone suggest me, after every single insertion/update, should we close the database or we should close the database when it is actually needed ?
Closing the connection throws away the page cache, and requires that the schema version is checked and the entire schema is re-parsed the next time it is opened.
In most apps, there are not enough database accesses so that the overhead of continually re-opening the database would actually become noticeable. But this is no reason to add useless code to your app.
Please note that the SQLiteDatabase object is reference counted. So if you are using a global open helper instance, you can keep the DB open with an extra getWritableDatabase() call, even when all your other code calls close().
You should close the connection after each query.
In .net (and in most other frameworks), SQLConnections are stored in the background anyway. It won´t hit your runtime.
Also: connection pooling is your friend.
I am doing an android app and I have an UI to show some data received from the server. The data is saved in the db in a controller.
When the app is started, this is what it is doing:
the controller instance is initialized on the Ui thread, it is singleton. The initialization is lightweighted. The UI will call the controller method to get the data saved in memory and show it.
having a worker thread to execute some controller method to read the data from db and save it in the cache in memory and notify UI after get it.
whenever there is some new data, the server will send a push to the client where an intentservice is started and the controller talks to the server to get the data and update the cache and after it completes, it notifys UI.
So the question is the 2 and 3, since both are running in different threads, so in order to make sure the db must be read and save in cache first, I have a flag in 3) so that before writing the new data in the memory, I always check the flag first. It will work but since I can foresee there will be more operations on the cache probably cross different threads and I really don't want to add the flag checking in all such places, so do we have any pattern/way to make sure the 2) always happens first?
sorry that I didn't find any similar post on it. thanks.
ok do one thing when your statement 2 is complete the execution at the last line of code call a broadcast receiver and inside onRecieve() method which is inside the BroadCastReceiver execute the statement 3.
My application has :
Activity A that reads from sqlite database
Service with notification that writes to the database
on clicking Notification, Activity A opens up
the reading by ActivityA is very small task(in reference to time taken to read)
but the writing by the service to the database is very long(it sometimes takes 5-10min)
now when the service is running and i click on the notification, ActivityA that has to read from the database cannot perform its reading as there is already a service writing to that database.
so activityA has to wait (for 5-10min) to read from database.
on researching further i came across this
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#beginTransactionNonExclusive()
when i try to implement this in my method inside sqliteopenhelper class i get error as my application uses min api 10. so how do i get this method working for api 10 or is there anyother way to have parallel database access
?
is there anyother way to have parallel database access ?
I think there is no special way how to achieve it. You should use classic Java synchronization for synchronized access to your database.
Most important thing is that you have to make sure you have only one connection to database (you can't write/read from two different connections in the same time). And try to think about an usage of Singleton. In this case (and also in others) it's very efficient and clean solution and you can avoid many problems with access to db.
You mentioned that your task can last 5-10 min.
In similar cases every user should know that you are performing some calculations in the background e.q. show some progressDialog, progressBar or simply start animation of image.
If you are showing some data for example in List this is good reason to use lazy loading.
Have look also at these articles:
Android Sqlite Locking
Using Singleton design pattern for SQLiteDatabase
I have an app (Android 2.2 Google API Level 8) that has multiple activities pulling data from a content provider (SELECT only database access).
It also has a service with a central blocking task queue accepting any database write tasks; activities can fire a service request (As intent) which places a task on a blocking queue for sequential retrieval by a single thread and execution. Database is around 4mb.
There is a single database helper which the service uses to call methods to interact with the database including writing to it; all SQL writes are carried out within the database helper.
All database writes are surrounded by a transaction.
All database reads have the cursor closed at the end of the method.
None of the Activities has a handle to the database object, they can only communicate via the content provider or the service.
Any AlarmManager fired tasks - like Activities - only use the service to pop an appropriate task onto the queue.
The service is the only class that has a handle to the database helper.
All database writes are only carried out via a task placed on a queue; I have exhaustedly checked that task execution is sequential being well aware of it being essential to avoid concurrent writes to an SQLite database.
During a run of task executions I consistently get one or two "database is locked" errors on attempting to write to the database triggered by a tasks execution of 'begin transaction'.
In attempting to track down the source of the lock I found that using dbhelper.inTransaction(), dbhelper.isLockedByThisThread(), dbhelper.isLockedByOtherThread() didn't help as they wouldn't indicate an unexpected database lock.
What I did find that worked in detecting a lock early was to create a method with beginTransaction() and setTransactionSuccessful without any actual SQL write code, within a try catch block that would log the issue - always triggered by beginTransaction().
I placed this database lock trap either side of each of the blocking queue task methods in the expectation/hope that I would find a singular culprit that was leaving the database in a locked state after finishing.
I could not find a consistent culprit. After drilling down through from the start of the task call through to the database write I found that a database lock could occur seemingly out of the blue without having been locked by the previously run task (All these tasks run in sequence under the same singular thread).
After looking at a number of other peoples experiences with database locking issues I've tried closing the database connection directly after the transaction has completed on all tasks but this didn't help, if anything seemed to get more database locking occurrences. Tried added a sleep between each task execution; not exhaustively tested but generally found that a delay of 3 seconds or above seemed to stop the database locks appearing. Tried disabling alarm manager fired tasks - didn't make any difference.
Impression I have is that some form of maintenance task external to my application is dropping in and locking the database periodically - perhaps delayed writing of logs. Obviously I'm less than keen on setting a task processing delay so I'm considering having a database lock retry task queue to reattempt database writing as necessary; much prefer to resolve but am running out of ideas.
Can anyone think of some principle or gotcha I've missed?
Is it in reality normal within Android and larger SQLite databases that you'll get occasional database locks?
Thanks
SQLite guarantees sequential access from multiple threads as long as you use a single database connection. How and where are you opening and closing the database connection?
I generally recommend opening the database once on startup, and never closing it. There's no benefit to closing, since the transactional nature of SQLite means that writes are flushed to persistent storage as soon as possible anyway.
I would check if some activity that calls the DB or calls other activity that calls the DB, has only one instance. Otherward it can lock itself, in some sense.
With regards to
Is it in reality normal within Android and larger SQLite databases that you'll get occasional database locks?
No, it is definitely not normal to get occasional database locks. From reading your story you say that you have both a service and a content provider pulling from the database, so it is possible that you are locking the database between the two accesses.
What I generally do is ensure that I handle all of my database access through the content provider. By having a single point of entry to the database you can ensure that every software component is using the same logic to access the DB. Would it be possible to have your service access the DB through the content provider?
It's also good to remember that by placing your DB behind a content provider, it can still be accessed by multiple threads at once. To ensure that you are accessing the DB only one thread at a time you could place synchronized constructs on the DB inside of your content provider. Obviously if you are doing lots of long writes/reads to the DB, locking in this fashion will absolutely destroy your app. Putting all of your DB code inside of the content provider will also give you a single point of debugging which would help you figure out if multiple threads are accessing the DB.
I have a SQLite Database in android that is accessed from a thread when the activity is running, and in the onPause() of the activity a new thread is created to save everything into the database with a different thread to avoid timeout issues. However, when I try to do so, I either get database is locked errors. How can I fix this? Since I need to access the database from a separate thread in onPause(), could I delete somehow my previous access to it since I wouldn't use it again?
You cannot access an SQLite database when it already has a lock on it.
To avoid this, Android gives you ContentProviders to handle this sort of thing.
You should implement your own ContentProvider to do this kind of thing.
That said, databases can NEVER be assumed to be threadsafe unless you manage the threads yourself. Avoid using the db like this. Instead, cache the data (on a stack, perhaps) and request access to the database with a callback when your current transaction is complete.
As far as I know SQLite does not support concurrent access, so you either have to have a dedicated thread to provide access, or you have to obtain a lock to the SQLite object instance.