Reputation: 171
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.
Upvotes: 1
Views: 5522
Reputation: 2439
Use getPosition method of the Cursor to see your item position.
cursor.getPosition();
Upvotes: 0
Reputation: 9284
I had the same problem where bindView was getting called multiple times (3 to be exact) for each entry in my cursor.. The fix I found was to switch my layout to a Relative Layout like so:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#666666"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:layout_alignParentTop="true"
/>
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape_gradient_2"
android:text="No Evidence Available"
android:padding="10dp"
android:layout_below="@android:id/list"
/>
</RelativeLayout>
Previously I had been using a LinearLayout and could not get it to work. The only way that I would get bindView called once per row with LinearLayout was to set a fixed height on the ListView. Since pretty much any LinearLayout could be recreated with a RelativeLayout you should be able to just switch the two and then just tell the ui where to place each element. I still don't understand why we have to do this and I spent the better part of a day figuring out the problem, but at least now it's been solved. I'm really surprised more people haven't seen the issue.
Upvotes: 3
Reputation: 1006819
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...
Upvotes: 2