views:

64

answers:

1

I was using some of the code from DeskClock and found that when I tried to modify the CursorAdapter that newView was getting called for each item. (I actually wanted to add a divider and it seems like adding the dividers separately is better than adding them into a single listView)

If I have 3 items I get the following behavior:

 newView - called with item: 0
  bindView - called with item: 0
  bindView - called with item: 1
  bindView - called with item: 2
  bindView - called with item: 0
 newView - called with item: 1
  bindView - called with item: 1
 newView - called with item: 2
  bindView - called with item: 2
 newView - called with item: 0
  bindView - called with item: 0
  bindView - called with item: 1
  bindView - called with item: 2

I would've expected newView/bindView to be called once per cursor item. But, that doesn't seem to be the case. This was kind of a problem for me because I wanted to select the appropriate view depending on the cursor data, but since bindView could be called before newView that doesn't work.

Is this some odd recycler behavior (or somehow normal/expected)? Or is there something broken with the code (I removed everything except the ListView and it's still doing this)? I'm not quite sure why you would try to bind views that haven't been created, and why newView gets called on the first item twice.

Thanks!

Btw, if someone has an easy way of adding dividers to ListViews I'd love to know. I was going to try to dig through the contacts example to see how they did it there if not.


Btw, in case anyone's wondering MergeAdapter was neat to mess around with and try (I'll use it in some other situations). But, I did just end up writing a single adapter that handles multiple views. It computes the type of each item (which is small), stores it in a map, initializes it at adapter creation, and updates it in notifyDataSetChanged.

Then you just need to have getViewTypeCount() return the number of possible views. And getItemViewType to return the type from the map (which is 0 based, so 0-getViewTypeCount()). If you can compute your type from the position you don't need the map, but doing this on the fly wasn't possible so I just pre/recompute when needed.

A: 

This was kind of a problem for me because I wanted to select the appropriate view depending on the cursor data, but since bindView could be called before newView that doesn't work.

Did you override getViewTypeCount() and getItemViewType()?

Is this some odd recycler behavior (or somehow normal/expected)? Or is there something broken with the code (I removed everything except the ListView and it's still doing this)?

Something definitely seems strange.

Btw, if someone has an easy way of adding dividers to ListViews I'd love to know. I was going to try to dig through the contacts example to see how they did it there if not.

In the end, how one adds dividers to ListViews depends almost entirely on what the criteria are for when dividers should appear. It is impossible to supply a one-size-fits-all solution.

For example, my MergeAdapter can be used for dividers, where each chunk of stuff between the dividers can be contained in its own ListAdapter. That works great for some scenarios. However, let's say that the divider is really determined by a column (e.g., category) out of a database query. Running lots of sub-queries per category to wrap each Cursor in its own SimpleCursorAdapter for use by MergeAdapter would be painful. Better would be to create a different sort of wrapping Adapter that can insert headings on the fly based on detected changes in the category value. I don't have a sample of such an Adapter on hand, though it is on my 18,000-item to-do list...

CommonsWare
I tried overriding getViewTypeCount() and getItemViewType() but while the behavior was different, it didn't seem to match what I thought it should be. I did try MergeAdapter and it does what I'd like though it causes a problem with the cursor when you update the list. When the ListView adapter is set to the CursorAdapter directly everything works, when I set the ListView adapter to a MergeAdapter (with a CursorAdapter and other views inside it) the cursor doesn't get updated... not sure if I need a managedCursor or if MergeAdapter needs to be modified.
William
I was able to add in some code for registerDataSetObserver(cursor) which will call BaseAdapter.notifyDataSetChanged or .notifyDataSetInvalidated (which by default does nothing). And that seem to make everyone happy. Is there a reason this isn't in MergeAdapter that I'm overlooking? Or is this just an unusual case?
William
@William: That's probably a flaw in `MergeAdapter`. I will look into it. Thanks!
CommonsWare