views:

353

answers:

2

I usually tend to define the model layer of my apps using POJO's, such as Article, Comment, etc.

I was about to implement an AlphabetIndexer in the adapter of one of my ListViews. Right now this adapter accepts a Collection of Articles, which I normally get from my wrapper around an SQLiteDatabase.

The signature of the AlphabetIndexer constructer is as follows:

public AlphabetIndexer (Cursor cursor, int sortedColumnIndex, CharSequence alphabet)

Since this doesn't accept a Collection or something similar, just a Cursor, it got me wondering: maybe I shouldn't be creating objects for my model, and just use the Cursors returned from the database?

So the question is, I guess: what should I do, represent data with Collections of POJO's, or just work with Cursors throughout my app?

Any input?

+4  A: 

I have run into similar issues. Right now, I am tending away from POJOs. Note, though, that you can create your own Cursor interface for a collection of POJOs, if you so choose.

CommonsWare
I know about that, but it seems a bit circular... creating a Cursor for a Collection that was created from a Cursor. :)
benvd
Oh, no question. That's one of the reasons I am tending away from POJOs and leaving things just in `Cursors`. In MVC terms, you wind up with dumb models and smart controllers.
CommonsWare
I decided to accept this as the answer, since I now use this approach. Specifically, I created a public inner class in my `SQLiteOpenHelper` for each table it has. Those classes contain a bunch of methods to prevent me from having to mess with column names or numbers. The performance difference is immediately obvious in `ListViews` with as little as a few dozen entries. Also, I seem to prefer `CursorAdapters` to `BaseAdapters`.I got the inspiration for this from your books (specifically page 102 in Android Tutorials 2.9), which I didn't have back when I asked this question, so thanks! :-)
benvd
+4  A: 

One vote for entity objects (POJOs). Passing cursors around, especially to the UI layer, feels so wrong to me (whether or not the Android sdk kinda implies doing it that way). There are usually several ways to populate your UI, and I tend to avoid those that directly use cursors. For example, to populate my custom list views, I use a SimpleAdapter and give my collection objects the ability to return a representation of themselves as a List<? extends Map<String, ?>> for the SimpleAdapter's constructor.

I use a pattern where each table is wrapped by an entity object and has a provider class that handles my CRUD operations associated with that entity. Optionally if I need extended functionality for the collections, I wrap them too (ie. EntityItems extends ArrayList<EntityItem>) The provider has a base class that I pass a reference to a DbAdapter class that does the heavy lifting around the db.

The biggest reason, other than personal preference, is that I want to hide this kind of code as far away from my UI as possible:

String something = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_CONSTANT));

If I see that kind of code inline in the UI layer, I usually expect to see much worse lurking around the corner. Maybe I've just spent too much time in the corporate world working on big teams, but I favor readability unless there's a legit performance concern or if it's a small enough task where the expressiveness is just enterprisey overkill.

Rich
"I use a SimpleAdapter and give my collection objects the ability to return a representation of themselves as a List<? extends Map<String, ?>> for the SimpleAdapter's constructor" -- that involves a lot of data copying, chewing up CPU time and generating garbage. That may or may not matter for any given app.
CommonsWare
I keep a close eye on things like that, and I cache the results of these kinds of calls so I'd hardly think that my use of a convenience function like this would incur a significant memory or cpu perf hit. This brings up question that maybe you can answer though. If I populate a HashMap and all my keys are initialized string vars and all my values are string properties of initialized objects, by calling map.put(key, value) aren't I just passing around pointers as opposed to creating a ton of new objects (garbage)? I would assume so, by I don't know Java well enough to answer that for myself.
Rich
Hey Rich. I also like the approach of having the UI agnostic to where the data comes from, and cursors code in the UI looks ugly to me too, but I can find a couple of reasons why they are needed. First, they are the most efficient way of linking data to things like ListViews. Second, to convert to a collection you have to iterate over your cursor linearly, O(n), create one object per row that you wouldn't in the cursor, and the GC will have to collect those at some point, but most importantly, you are loading your entire collection in memory. Cursors only hold the current row.
palako