Performance problem with SimpleCursorAdapter in android - android

I'm trying to show a ListView filled with a SimpleCursorAdapter. The SimpleCursorAdapter receives a Cursor filled with the execution of a rawQuery like:
SELECT DISTINCT s.cod AS _id, s.name AS name FROM supplier s
INNER JOIN product p ON p.supplier = s.cod
INNER JOIN productprice pp ON pp.product = p.cod
WHERE
pp.category = 'w'
ORDER BY s.name
When I execute this query directly in the base, it returns 40 rows in less than 0.1 sec (normal). The execution of the rawQuery in the repository is very fast too. The problem is when I do the myListView.setAdapter(simpleCursorAdapter);. It takes more than 2 minutes! So i've changed the query to SELECT cod AS _id, name FROM supplier ORDER BY name and the execution of the setAdapter was pretty fast ("normal fast" hshs).
My questions:
Exist a limit of JOIN's that I can do in a rawQuery to fill a listView? Am I doing something wrong? Should I use query() in the repository instead of rawQuery()?
Sorry about the english and thanks in advance.

The Cursor you provide to the SimpleCursorAdapter is a resultset from the database query. If the database query is fast, then the problem is located in the CursorAdapter. I have experienced that CursorAdapters have poor performance (both using SimpleCursorAdapter and custom adapters extending CursorAdapter or ResourceAdapter). I ended up pulling the data from the Cursor, put in in an array, and extend the ArrayAdapter, which gave me much better performance.

Related

SQLite: getCount() or DatabaseUtils?

I am trying to test if a sqlite database is empty or not. I've read stackoverflow posts and many recommend using rawQuery and getCount() methods. Others recommend using DatabaseUtils.longForQuery and DatabaseUtils.queryNumEntries.
I am looking for speed since the number of rows in the database is large. I am looking for quick test to see if the number of rows is zero. If not, it is because there are 1 or more rows in the database. Would there be a method that aborts the count after 1 row is identified rather than counting all of the rows? If not, any thoughts on getCount vs. DatabaseUtils?
queryNumEntries as Google Doc where Added in API level 11
long count=0;
Cursor cursor = Database.DB.rawQuery("select count(*) from table;",null);
count=cursor.getLong(0);
The sql query SELECT COUNT(*) FROM table_name; runs pretty fast.
DatabaseUtils.queryNumEntries() uses this method. I would go with that.
You could run your own SQLiteDatabase.rawQuery() that does the above query. That should be good too.

ORMLite union operator

I have three tables that I have to present in one Android ListView. To get the data I use the SQL UNION operator to "merge" all three tables together, so that in my ViewBinder I can make each timeline item look distinct.
These items need to be sorted in chronological order. These three tables do not have a common base class.
Here is the SQL that I have in mind:
SELECT * FROM (
SELECT id, startTime as time, username, comment, "CustomerInteraction" FROM CustomerInteraction
UNION
SELECT id, date as time, "" as username, "" as comment, "Sale" FROM Sale
UNION
SELECT id, claimDate as time, username, comment, "TravelClaim" FROM TravelClaim)
ORDER BY time DESC LIMIT 100
How can I express the above query in ORMLite?
I know I can use Dao.executeRaw, but I don't want to populate my entire list in one go. I would much rather use the trick to get the underlying cursor from ORMLite, and then just pass that to my Adapter. (Lazy loading, makes initial display of long lists much faster.)
Is there a way I can do something like Dao.getPreparedQueryFromRaw(String statement) ? Or better yet QueryBuilder.union(QueryBuilder qb)?
You can get a Cursor by calling rawQuery on the SQLiteDatabase. I do something like this:
final SQLiteDatabase db = getHelper().getReadableDatabase();
Cursor cursor = db.rawQuery(MY_SQL_QUERY, null);
You don't need to do anything much more than that.
Is there a way I can do something like Dao.getPreparedQueryFromRaw(String statement) ? Or better yet QueryBuilder.union(QueryBuilder qb)?
The best way to do this with ORMLite is with one of the the queryRaw(...) methods. They return a GenericRawResults class which you can iterate across. The iterator gives you a number of different methods to help with moving around the list.
The problem is that the generic results are not of a certain type so I'm not sure if you can map it into the Android ListView. You can provide a RawRowMapper to queryRaw(...). You can get the mapper for a particular type by using the dao.getRawRowMapper() method.
Hope something here is helpful.

Android: column '_id' does not exist

I am getting this error
IllegalArgumentException: column '_id' does not exist
When using a SimpleCursorAdapter to retrieve from my database, and the table does indeed have this _id column. Noticing this a common problem, I have tried to work around it given some of the solutions online but none of them work. This is my cursor query:
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, R.layout.quoterow, myCursor, new String[]{"_id", "quote"}, new int[]{R.id.quote});
although I should mention the original did not include the _id column, I added this recently to try and solve the problem. Has anyone got any ideas that might help solve the problem?
Your database doesn't have to have a column called '_id' but the SimpleCursorAdaptor does need to have one returned. You can do this with an alias.
An example is that I have a table with columns...
uid,name,number
To query this for a SimpleCursorAdapter, I do this with a database rawQuery...
SELECT uid as _id,name,number FROM MY_TABLE
This works fine and supplies the necessary '_id' column to SimpleCursorAdapter.
EDIT: As far as I understand it the _id field is used as a unique key to make sure the data the cursor handles can be handled correctly by adapters and adapterviews etc.
Look at the data model in the docs for Content Providers.
Using a unique key in 'databases' of whatever kind is pretty much universal practice, and as far as I can tell, the use of the column name '_id' (or '_ID') is simply a way of standardizing and simplifying things across databases, content providers, cursors, adapters etc etc
In short, in order for these various components to work correctly, they need a data column with unique values but they must also 'know' what the name of that column is. They wouldn't 'know', so to speak, that my column name 'uid' is the one they need as opposed to my 'name' and 'number' columns.
You either don't have a column "_id" in your table or you are not including it in your query. That is what is causing the exception. You need to fix the following as well:
Your last argument for the CursorAdapter constructor is missing the to column reference for _id.
The int[] argument is an array of view ids to populate with values from the cursor. The String[] argument is an array of column names from a row the cursor points to.
You have to have an equal number of values in the from array as you do the to array. Because the data from the Cursor is being grabbed FROM the Cursor and placed TO the views. If there are not an equal number of values in each array, the adapter throws an exception because it doesn't have the right amount of information to map the data to the views.
Also, according to the JavaDoc for SimpleCursorAdapter, that constructor is deprecated because it causes queries to be executed in the UI thread. Which is bad. Use this one instead:
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html#SimpleCursorAdapter%28android.content.Context,%20int,%20android.database.Cursor,%20java.lang.String[],%20int[],%20int%29
A simple fix would be to add ",0" to the end of the argument list.
If you are trying to use an existing sqlite database in your Android application then you need to do some prep work to get it to work properly. This blog post describes the process in detail.
http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/

Android's SimpleCursorAdapter with queries using DISTINCT

Here's an interesting question that I'm shocked hasn't been asked more often on the internet. Android's CursorAdapters are extremely useful once you get a ContentProvider up and running and learn how to use it, but they are limited due to their requirement on having the _id field as part of their query (an error is thrown without it). Here's why:
My specific problem is that I have two spinners: One spinner should contain unique "category" names from the database, and the other should populate with all the database entries from the selected "category" (category being the column name, here). This seems like a pretty simple setup that many programs might use, no? Trying to implement that first spinner is where I've run into problems.
Here's the query that I would like for that first spinner:
SELECT DISTINCT category FROM table;
Making this query throws an error on CursorAdapter because the _id column is required as part of the query. Adding the _id column to the projection naturally returns every row of the table, since you're now asking for distinct id's as well, and every id is distinct (by definition). Obviously I would rather see only one entry per category name.
I've already implemented a work around, which is to simply make the query above and then copy the results into an ArrayAdapter. My reason for this post is to see if there was a more elegant solution to this odd little problem and start a discussion on what I could be doing better. Alternate implementation suggestions, such as using different kinds of controls or adapters, are very welcome.
Here's the query I ended up with:
SELECT _id, category FROM table_name GROUP BY category;
I used the rawQuery() function on an SQLiteDatabase object to carry this out. The "GROUP BY" piece was the key towards getting the right results, so thanks to user Sagar for pointing me in the right direction.
Do consider user Al Sutton's answer to this question as well, as it may be a more elegant solution to this problem.
Thanks everyone!
I'd suggest having a separate table with just _id & category in it which contains one row per unique category. Your data rows can then replace their category field with the _id from the category table.
This has the added advantage you can change the category in the categories table and it will show up in all entries in that category.
SELECT DISTINCT category,_id FROM table GROUP BY category;
I think this should give you what you are looking for. The results from this will be the category, and the first _id for that category. You can ignore the second column (_id).
You can specify an _id field alias in your select statement that is just a constant value, for example:
SELECT DISTINCT 0 _id, category FROM table;
Better yet, I solved this problem by using:
SELECT DISTINCT category AS _id FROM table
Now, you have a column with the name _id which has what you want in it

How to join a ContentResolver Cursor with a Database Cursor?

I get records from the system by quering a ContentResolver. I maintain the order of the items in the database. So I want to display the items in the order taken from my database.
How do I merge these two informations?
EDIT 1
I am looking after an alternative way now. As what I ideally want is:
get order of contacts by a custom order held in my database (this involves joining CR with my DB cursor, and doing an order by, later seams it's not possible with CursorJoiner)
but there is more, if the join is not unique I want to sort by contact's name as last measure
which is impossible using Cursor and Joiners, because of the missing feature of order bys, also I need to return a Cursor, as I will be using the in an ExpandableList
Also this translated to TSQL it would look like
select * from contactsdata
left join category on contactsdata.catid=category.id
order by category.pos asc, contact.display_name asc
So I am looking now after an alternative.
I have in mind to load in a temporary DB table all data from CR, then do the query on the temporary table where I can join tables and do order bys? How does this sound to you?
Take a look at CursorJoiner.
If that doesn't work, you can roll your own equivalent with a fair amount of pain, whiskey, or both.

Categories

Resources