Android using a cursor on UI thread - android

I am wondering when or if its ok to use a cursor to get data from a sqlite database on the ui thread. Basically I use a cursorloader to get a cursor. And then I want to do something with that cursor. Is it ok to do something with the cursor from the main ui thread? Really I just need to read one row from the cursor.

Retrieving a row from a Cursor is not an expensive operation... querying the data from the database, on the other hand, could be time-consuming depending on the amount of data you are requesting and/or the complexity of the query. CursorLoaders query for Cursors asynchronously so your approach is fine.

It's OK. It's not a network operation.
EDIT: by "it's OK" I mean that Android 4.x won't force-close your app for doing that, like if would for performing network I/O on the main thread. Depending on the query time, it might or might not be appropriate to stall the UI thread. For a "get a single row from a single table by its primary key" kind of query, it's perfectly fine. For a hairy query that takes a second or more, consider a background thread and a progress dialog.

Related

Setting initial values for SQLite in onCreate() of SQLiteOpenHelper

I am creating an Android app for which I need to create a SQLite DB and pre-populate it with some values.
The Android documentation says this about what to do in "onCreate" of the SQLiteOpenHelper:
Called when the database is created for the first time. This is where the creation of tables and the initial population of the tables should happen.
Reference - http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onCreate(android.database.sqlite.SQLiteDatabase)
I am doubtful about the following 2 things -
What is meant by "when database is created for the first time"? Is this done on the first launch of the app or only when the first DB request (read/write etc) is done.
If it is the latter, I fear that it may take quite some time to create DB, pre-populate it with values (I have about 60 rows to be inserted into 1 table) and then read the DB to show it. Is this the best practice?
I have been doing all my DB operations in AsyncTasks. But I am doing the table creations in onCreate using "db.execSQL" statements. Is this fine (in terms of convention/ performance) or should I go for an AsyncTask here as well?
Any help is appreciated.
1) The later. It is done on the first read or write to the DB.
Your fear might be correct, this is why you can ship your app with a database that's already populated. Or you can launch an AsyncTask with a simple SELECT 1 FROM anytable query. More about shipping with DB here. (60 rows is nothing to fear about tho, and you can safely just keep using AsyncTasks).
2) Yes it is fine. The onCreate logic will run when you first read/write the DB, so it if you always use AsyncTasks onCreate will run in an AsyncTask also.
What is meant by "when database is created for the first time"? Is this done on the first launch of the app or only when the first DB request (read/write etc) is done.
It happens when you first query from database in general term. After that only Upgrade method is called that too when you change the db version.
If it is the latter, I fear that it may take quite some time to create DB, pre-populate it with values (I have about 60 rows to be inserted into 1 table) and then read the DB to show it. Is this the best practice?
60 rows insertion is not a big task. More you can read about beginTransaction(),commitTransaction and endTransaction for insertion. It will make your insertion task lighting fast.
I have been doing all my DB operations in AsyncTasks. But I am doing the table creations in onCreate using "db.execSQL" statements. Is this fine (in terms of convention/ performance) or should I go for an AsyncTask here as well?
It good you are doing you Db operation in AsyncTask and its completely fine.
Speaking of DB operations:
Performing DB operations in AsyncTask is not a good approach, generally. As you might encounter a problem called "memory leak", and it might come as a silent assassin in the night.
There's lot written on this issue. Just google "asynctask leak context" and here you go.
So how to perform DB operations?
Using Loader API in conjunction with ContentProvider is considered good approach for querying database. Loader asynchronously queries your database and delivers the result to specified subscribers. Configuration changes or other sudden stuff does not bother it.
And it is really convenient to query your data using loader API once you know how to do it.
Single inserts/updates/deletes might be done directly from the main thread via ContentResolver. These calls will be blocking (synchronous), but I bet you user would never notice anything while the amount of data is not large.
If you're operating on a large dataset, and you fear you'll be significantly blocking UI thread, I'd suggest using IntentService or any custom Service capable of doing operations in background (note that by default Service operates on main UI thread and you have to specify background operation yourself or use IntentService)
Speaking of DB initialisation:
You might create a one-time IntentService, if you're initialising a large set of data. It will handle your request asynchronously and, for example, perform a broadcast that the application is set up and ready, so you might stop a "wait a sec, performing app initialisation" screen and show user your data.
There's also nothing wrong with shipping your database along with application, though it appears to be a bit hackish solution.
Either way, you choose what is more suitable for you.

Why is the UI thread blocked when work is done on a separate thread?

In my app, I have a ViewPager with +/- 10 pages. When the app is first opened, all the pages are instantiated and immediately begin to load data to display. Each page (which are fragments) creates an AsyncTask to query a database and populate itself with the appropriate data. Here's the problem: even though the work is being done on separate threads, the UI stops updating during the database queries (which are done sequentially, and take 1-3 seconds total). This happens both on my Nexus 5 and a crappy old Samsung phone, so I know the problem is not that the hardware just can't keep up.
So ultimately, I'm wondering why the UI thread is blocked by work done on a background thread. My understanding of threading was that doing work on one would not block the other for an extended period of time. If my understanding is wrong, please explain how. Thanks in advance.
I don't think code is required here, but if it is, let me know and I will post the relevant portions.
It stops animating immediately after the first database query begins and starts animating again immediately after the last database query completes
It is possible, then, you are not doing the work on a background thread that you think you are. You may be doing the work on the main application thread.
Traceview can help you identify what you are doing on the various threads, and StrictMode can help you with obvious problems (disk I/O and network I/O on the main application thread).
In this case, you may be getting caught by how you are doing your work:
Each page (which are fragments) creates an AsyncTask to query a database and populate itself with the appropriate data.
If you are doing your query in doInBackground() but are not touching the resulting Cursor also in doInBackground(), the query actually wasn't done yet. The Cursor is a SQLiteCursor, and it lazy-executes the query when the data is first used. This is another one of those "really cool ideas that just plain suck in how we do things nowadays". A workaround is to call getCount() on the Cursor while you are in doInBackground(), to ensure that the query actually is executed on the background thread.

Keeping database queries from ContentResolver and SQLiteDatabase from blocking each other

My app runs some very complicated queries using joins and other things which the Android ContentResolver is not equipped to handle. Some of these queries, inserts, etc can block the UI thread, so I run them in the background. As you might guess, this can cause a SQLiteException (database locked) when the timing of two sql requests coincide with one another (the most common cause of this is data loading into my db from our server in the background while the user requests to view data from the db on the screen).
The best way to fix this issue is to keep all DB activity on one thread, but like I said above some inserts in particular would cause some big time UI thread blockage, so that's not really realistic. The other option I've seen is synchronizing all the methods of the ContentResolver (they all should share a common member variable like a DatabaseHelper). I've done this, but again, this is not enough, because for some methods I have to use the SQLiteDatabase object's rawQuery() method to pull off the sql I need to get the data.
Is anyone aware of a strategy I could use to synchronize both ContentResolver methods and SQLiteDatabase methods? Thanks a lot!
I would make the long inserts in a transaction
db.beginTransaction();
try {
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
If you don't want that the requests that a user makes during the insert returns empty content, implement a logic of retry.
Would not this work ?

When should I do certain SQLite operations on another thread(not the main thread)?

My Android application includes an SQLite database with an SQLiteOpenHelper class to help manage it. During application use, the user may perform some operations such as adding/deleting/updating etc on the database.
At some points the size of the operation will be known, like this:
user clicks button to save item
the SQLiteDatabase performs a single insert query
user continues using app
At other areas of the app, the operation may be large, like inserting 10+ items into the database all at once.
Questions:
should I thread simple operations like inserting/updating/deleting/viewing 1 item?
will it take longer to insert 1 item into a table which contains many items(like 30+) than it would take to insert into a table with no items?
if i don't need to thread such simple operations, at what point do you suggest i start threading them?
when i say thread i mean using a thread that is not the main UI thread.
edit: I realize that small operations do not take much time and i could very well get away with doing them on the main thread. I am just concerned that it would be bad practice to be executing them on the main thread and would like clarification!
General rule for everything: If it's fast enough, do it on the main thread. If not, use a worker thread.
Unless you have a ridiculously huge database, a single operation almost never warrants a separate thread. Databases in general are designed to scale well, but of course a very big database (10,000+ rows?) will be a bit slower than a small one. 30 rows, however, is nothing.
I would start threading stuff if you have a lot of operations going on, like a bunch of queries, or complicated queries that span several tables.
As with everything - profile your app, and if it's too slow, optimize. Don't write an awesome synchronized super-duper multi-core-ready database handler if none of your queries takes longer than 2ms.
Always measure before you optimize!
Make sure that DB operations you do affect user experience and than start looking for a solution.
If database stuff gets slow, then use AsyncTask, which was designed to perform tasks in the background, and then update the GUI on EDT.
There is absoulutely not reason to use a thread here. Just return the cursor, extract the information from the cursor and return it to the main activity.
Specifically speaking a thread is something ideally that is going to repeat until something happens or it times out. Since the database you are using i'm assuming is on the phone, it would take practically zero time to access it.
Also another thing you can do is create a Utility class to assist with your activity to database interaction. It would be what your activity calls to interact with the database. Specifically the flow of control would be like this:
Activity -> Utility -> Database
Its between the activity and the database to keep them isolated from each other and make it much easier to access whatever it needs since it doesn't have to go directly to the database itself.

Does reading of a Android Cursor go all the way to the database?

I've got a kind of heavy Android application and want to make sure not never ANR it.
I've moved my database queries away from the UI thread (to AsyncTasks), but I still read from the cursor in the ui thread since I suppose the returned cursor is stored somewhere in memory, i.e. the actual reading of it does not go the entire way to the database. Is that correct or do i really need to move all reads of the cursor to non UI threads as well?
To be more specific:
Does for example http://developer.android.com/reference/android/database/Cursor.html#getInt(int) read from memeory, or does it aquire some kind of read lock from the actual SQLite database.
I guess the Cursor implementation in my case is an SQLiteCursor since the ContentProvider is implemented using an SQLite database.
When you call query() or rawQuery() on a SQLiteDatabase, a Cursor is returned immediately, because the actual query itself is delayed until you start using data. Any call that manipulates the Cursor or needs data that implies that the query is executed (e.g., getCount()) will actually execute the query. Hence, it is best to "touch" the Cursor in doInBackground() while you are on the background thread.
From that point forward, though, the entire result set is in memory, for result sets under 1MB.

Categories

Resources