I have a (hopefully) quick question regarding handling SQLite database connections in Android. I have an app that is composed, naturally, of several activities. I have no trouble creating/updating/querying the database, as I've created a single, dedicated class to handle that work via SQLiteOpenHelper, etc.
My question is this: since these activities all share this same database, is this usually implemented as a single, static member, or should each activity own its own connection? My concern of course is the cost of re-connecting to the database in each activity.
Or, put another way, is there any reason not to just store a singleton instance?
I'm also wondering if there's something going on behind the scenes similar to .NET's connection pooling to reduce the cost of opening connections.
Thanks in advance!
Connection opening in SQLite is about 0.2ms.
The best practice tells us to open and close the connection each time we need one.
Just use SQLiteOpenHelper.getReadableDatabase() and SQLiteOpenHelper.getWriteableDatabase() - Android will manage and cache the connection so you don't need to.
In fact, refer to the official Google Using Databases documentation:
To write to and read from the
database, call getWritableDatabase()
and getReadableDatabase(),
respectively. These both return a
SQLiteDatabase
Related
I am planning on writing an application that saves a fair amount of data. Historically, I have simply written data directly to a server, and only used some simple key/value storage with shared preferences for local storage.
I am considering this time, instead, using SQLite to save the information at first, and sync the data to the server in the background later. This will benefit the user in a few ways: 1) can use the app offline 2) don't have to worry about data being saved right away, it happens when ever it can 3) more reliability.
My approach will be to get/set data from SQLite during UI usage, and use a background process to find new rows and put them on the server, flagging them as synced when it happens.
Does this sound reasonable?
You can use SQLIte for your scenario. But, while implementing, you can follow any one of this approach.
Approach #1: Use an Abstract Factory to Instantiate the SQLiteOpenHelper.
Approach #2: Wrap the SQLiteDatabase in a ContentProvider
Refer to this link for how to implement these 2 approaches. http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html
Key points to be noted while using SQLite
Sqlite takes care of the file level locking.
Many threads can read,one can write. The locks prevent more than one
writing.
Android implements some java locking in SQLiteDatabase to help keep
things straight.
If we handle the database incorrectly from many threads and mess up the code, your
database will not be corrupted. Only few updates will be lost.
How "Multiple Threads - DB access" can be used for your scenario
The SqliteOpenHelper object holds on to one database connection.
If you try to write to the database from actual distinct connections (multiple threads) at the same time, one will fail. It will not wait till the first is done and then write. It will simply not write your change. Worse, if you don’t call the right version of insert/update on the SQLiteDatabase, you won’t get an exception. You’ll just get a message in your LogCat, and that will be it.
So recommended to write using single thread and read from multiple threads if necessary for faster access.
Does this sound reasonable?
Yes. Note that the synchronization process can get tricky (e.g., what happens if the server hiccups halfway through?), but that has mostly to do with synchronization and little to do with SQLite.
We implemented a solution that used a SQLite db on the device to sync data via a web service to the master database. We did this for a couple reasons: offline, poor connection, manual sync.
For our solution we had a flag on the table that determined if the data was pushed to the web service. Our web service also provided data back to our application to let us know if the data was received and processed correctly. This allowed us to clean up the data on the device, send notifications if there were failures, and resubmit the data if there were previous failures.
You can use push notifications as well if you have fixed the issues on the backend and have the device resend the data to the web service. This worked really well for us.
I'm writing a small application for Android and I'm using GreenDAO as my ORM. I wonder how long should I keep my session open? I have several activities that read/write data from database and I see the following possibilities:
Keep session open per Activity basis: created in onCreate and closed onPause/onStop
Keep one session open in all activities and just pass it somehow between them.
Open session in onCreate, read all the data necessary to populate list view and close while still being in onCreate - I think this forces me to read all the data at once, which can slow down application considerably though.
Which option do you think I should choose? Maybe there's some other, canonical way of doing this?
I found a comment to this article:
http://greendao-orm.com/documentation/how-to-get-started/
where "DaoMaster" recommends application scope dao sessions.
He also talks about using Singletons, but I would not recomentd Singletons in Android unless you realy know what you're doing, because Singletons work a little different then on the jvm.
I have a an application that has 2 parts.
A service which creates content.
An application that uses the content
Each of these run as different processes. The problem is that both of them share a database. And I frequently get database locked error, both when the service tries to write something and the UI is reading data. Also vice versa.
How do go about this?
The class used to access DB is a singleton class. But since both UI & the service are 2 different processes, there are 2 singletons I presume. So that doesn't help.
Even synchronise won't help I suppose, since again because of 2 different processes.
Content Providers maybe an option, but since I use complex queries to dig info, it would be really hard to use that too.
How do I get the two processes share the database.
Any cues would be greatly appreciated.
Using a content provider is one option. Another is to take a look at Berkeley DB. The BDB SQL API is SQLite compatible and the BDB lock manager allows multiple threads and/or processes to read/write to the database concurrently.
close the connection after each operation
catch the database locked error and try to reconnect after 50ms
or let the service handle the database and the activity ask the service for data
may be there is isDatabaseInUseMethod ?
You should use a content provider to funnel your database queries through one source. Inside of the content provider you can use any locking mechanisms you would like to ensure you're not having concurrent access. You may also think about using content observers to coordinate service actions with changes to the database.
The following is a great article on how locking works with SQLite on Android and what things to be aware of: http://kagii.squarespace.com/journal/2010/9/10/android-sqlite-locking.html
I would think you'll find some answers there :)
We all learn that resources, such as database connections, should be acquired late and released early.
Yet applying this principle to SQLite database connections on Android have caused me some headache.
I have an app that download updates from a backend server in a service working in the background, writing updates to the database at a regular basis. The problem I experience arise when the following sequence occurs:
Service opens a writable database connection
Some activity opens a readable database connection
Service closes its database connection concurrently with the activity reading data
Activity fails due to its database connection was closed
Both the service and the activity uses the same SQLiteOpenHelper class, though different instances, to open their connections. My initial assumption was that this should work just fine, but somehow it seems that the underlying connection is shared between the two database instances.
To work around the problem I ended up not closing the database objects, only closing any opened cursors. This seems to work, though I'm not sure that I'm not leaking memory here.
Is there something obvious I am missing here?
Is there something obvious I am missing here?
I'd say no. Looking at the source code to SQLiteOpenHelper, I can't see how two instances could be sharing a SQLiteDatabase object.
Some diagnostic suggestions:
Dump the toString() value of each SQLiteDatabase, which should give you a Java instance ID. If they are the same, that is where your problem lies, and you will need to work your way upstream to figure out how the heck this is happening (e.g., you really are using the same instance of the SQLiteOpenHelper).
With your database in a stable state (i.e., no need to create or upgrade), flip one of your two database spots to use SQLiteDatabase directly, rather than via SQLiteOpenHelper, and see if that changes matters.
I am working on a program that has the following situation.
You want to look up a recipe, so the Activity will call the db ContentProvider.
The recipe isn't stored locally, so it will call out to a web service to get the data.
This data will be stored in the database as I am assuming that if you don't want to keep a local copy you will choose to delete it later, but you may want to shop and cook without going to the Internet constantly.
So I think my design may be getting overly complicated.
I currently have a Service that will call the REST service, and a ContentProvider to go to the database.
I am now considering replacing the Service with a ContentProvider, as I don't need a long-running Service as it should infrequently go out.
So, the Activities would call the db ContentProvider, and if the query is empty then the ContentProvider would call the REST ContentProvider, as the Activity shouldn't care where the data comes from, and the db ContentProvider would then store the information before returning back to the Activity.
Is this the best approach for my scenario, or is it bad form to have ContentProviders chained together?
I think that is quite reasonable. However, I think you could still keep the Service but just always expose the data through the ContentProvider. One glitch here is that you will have to start(or bind) the service in the ContentProvider and you will have problems when testing your Provider using ProviderTestcase2<Provider> as the MockContext does not support starting the service.
It seems a good approach. Currently I'm developing something similar and I've found this great article, where the author explains everything step by step, saying which thing for what is used for, what is the best approach and so on. Take a look at it if you are having some troubles implementing something:
http://programming-android.labs.oreilly.com/ch11.html