I have an Android app that displays user SMS's in a threaded conversation format; that is with each item showing the display name (if available), contact photo, MSISDN and timestamp/teaser for the most recent incoming or outgoing message in the conversation.
Problem is that it's actually not so easy to do this in Android. Querying the threads directly returns limited information, so timestamps, for example, are not available. Querying all messages will return all the data I want, but then I have to sort through it all, find the most recent message, tot-up conversation size totals and so on. As an added complication, drafts are custom (not the standard ones held with all the other messages) and also have to be added to the mix.
This latter approach has led to a monstrous approach, using the latter, whereby I grab everything, sort through it all which sees the data go from a Cursor to HashMap to a List and finally an adapter is used for display purposes. This naturally leads to a serious performance issue whereby the user has to wait a few seconds for the screen to refresh.
So the question I have is whether there is a more efficient way of doing this, for example querying the messages using raw SQL, that would not result in such a big hit on performance?
Mock the return from the cursor for one to rule that out. Also you could try an iterator for the hashmap instead of creating a list? I don't know how your structure is setup to allow paging or something similar.
Thanks for that Giblet. I was rather hoping that I could simply do some form of raw SQL query of the messages, as this would eliminated any need for hashmaps, mocks or the like. Documentation on this is typically very limited of course.
Perhaps all I have open to me is the option to simply make my existing code more efficient, which no doubt is possible as looking at it, it's a bit of a mess.
Do you grab everything each time there's a new message? Have you tried using a content observer to check for changes in the SMS database and alert you when there is? Then at this point check for only the changes and then add them to your own hashmap and adapter without the need to reiterate through the entire SMS database?
You may be doing this already anyway?
I simply query the messages when there's a refresh of some description; be it onstart, onresume or upon an orientation change. I could create a duplicate of all the messages in a local SQLite schema, which would be easier and more efficient to query, but that's a can of worms (appkillers can really screw up your synchronization of duplicate data).
The more I look at this, the more I feel that Google didn't think it through very well. You can 'query' conversation threads, via a content URI, but what it returns is limited (you get the message for the most recent message, but bizarrely not a timestamp and no way of ordering them by latest message).
Ideally, there should way of simply getting a simple cursor object with conversation data (thread_id, address, date, body, type, etc) that can be sorted by any of these, but there does not appear to be.
Looking at my code, I do think there is room for improvement as it has grown organically (and thus is a bit of a mess at this stage), however, I was hoping that there was a simpler way of going about this.
The SMS stuff is still all private bar a few SMS methods so technically shouldn't be used at all as there's no support for it and no promise that it will be available on all devices and is likely to be replaced in future versions so its not really to be viewed as a full API.
In saying that the SMS API is a long time coming!
What I do is query and retrieve all the SMS data I need on App start much the same as you I'd imagine but then I set up listeners for outgoing and incoming SMS and using these I add the extra information with what I retrieve when I detect a new SMS, it saves me querying large amounts of content each time.
But it sounds like that might not be an option in your case?
I could certainly query the messages from the content provider and then pop the relevant info in a custom schema each time it starts up, but this would still have to happen whenever the app starts and that can be a killer, usability-wise.
Unfortunately it appears that my best bet is to simply rewrite that portion of the code to better optimize it so that the delay is minimized. There are no easy answers, I'm afraid.
Looks like it Is the app available on the market?
Looks nice, on the time stamp issue have you tried getting the date from the SMS content and converting that into a time stamp?
Thanks, but as it was more a learning experience than a real project, it is less than optimum. And as it makes no money I am not going to spend any time rewriting it.
You have to take care with timestamps as there are generally two; one is your timestamp and the other is theirs (or their SMSC), and so you have to be careful to be able to access the former as the latter will cause issues whenever the sender is in another timezone or your clock is slightly out of whack with theirs.
Additionally the principle problem I have is with the information that the Android content providers are willing to return. "content://sms/conversations" will only return thread_id, msg_count, snippet (a teaser of the last message) - which are not much use in so far as they are missing the magic timestamp with which to order everything by - otherwise they are ordered, by default, by thread_id.
I may have found an answer though; "content://mms-sms/conversations" appears to return a lot more data, from what I've read, although I would need to play around with this to see how well it works. Something for the weekend, I suppose...