Sometimes in our apps we have the need to link to data of other sources. You have a database of your own for your app, but some records also point to the MediaStore content provider to calendar entries or to contacts.
For all detail pages this is not much of a problem. You get the data from your database and query the external content provider for additional data based on the id or lookup uri that you stored in your database.
But what to do, if you want to show data in
ListViews? Say contact pictures, event titles for multiline list elements and so on. Then it gets complicated.
From what I see, we have the following choices. Neither is fully satisfying – which is why I would like to hear how you deal with these kind of problems.
- You get a list of all elements of the
ListViewby querying your database. And you query the content provider for each list entry using an
AsyncTask. This is the a very memory efficient solution.
For images (album covers, contact pictures…) this is probably the best option. Especially if combined with an in-memory cache. Even if users would love to see images immediately, they know this is not feasible and accept some lag before images are displayed.
But not so for any text elements. The second line of a multiline list element should be visible instantaneously. So for text this option is not acceptable.
- You could query the content provider for all entries at startup, put them in a HashMap and use this map later on. Well this might work if the content provider has only a few entries. But there might be thousands of media files on a SD card or thousands of contacts for a big company. In cases like these this won’t work. It would be a big waste of memory – especially since you probably only need very few of these rows at all.
The Hashmap would also need too long to be created in the first place. The waiting period for the inital screen would be inacceptable. So this is basically a no-go.
- You could keep redundant data in your own database. For every record that contains a link to the external content provider you also include the data, you need in the listview (e.g. the band name). That’s the option I have chosen. You only cache the results you actually need.
There are two drawbacks to this solution: First you are wasting device memory. That is flash memory not RAM. No problem for most high end devices but low cost devices often have very limited memory available.
Second you have to sync the data whenever your app restarts. If your app stays in the background for quite a while, the user might have changed the external data source. In fact this might even happen while your app is in the foreground if a sync adapter changes values based on changes of the backend. Now your list reflects the wrong values until your database has re-synced with the external provider.
You could choose to listen to changes in the content provider in a service and update your database when needed. Activities then could query for changes.
Whether these two issues of this option pose problems for you depend on the type of app. In most cases a correction of a changed value later on should be okay. And if you do not have hundreds or thousands of rows in your own table the inefficiencies are not that bad as well.
Now I would really like to hear what you think. Probably there are other options, I have overlooked. Or better ways to make one of these three options work. Please let me know in the comments, on G+ or on Twitter. Thanks!
If you are curious about the G+ discussion, have a look at my G+ announcement of this post.