I had this weird scenario where every time I select a value from the spinner in the ListView
's 1st Item, the last ListView's
item its spinner value is the same as the first item. This will only happen when the total number of ListView items is 5 and above. I commented out the codes and retain just the declarations and it's still happening. Is this a bug in Android?
Clarifications:
- My ListView's
Scroll Listener
is empty - My spinner's
setOnItemSelectedListener
is commented out. - Android SDK Tool version is 22.6.2
Android SDK Platform-Tools is 19.0.1
Here's the adapter code:
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
Viewholder v = new Viewholder();
v.rowView = convertView;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (v.rowView == null) {
v.rowView = inflater.inflate(R.layout.inner_base_header_cutom, parent, false);
v.spinner = (Spinner) v.rowView.findViewById(R.id.spinner1);
v.rowView.setTag(v);
} else {
v = (Viewholder) v.rowView.getTag();
}
return v.rowView;
}
ViewHolder:
class Viewholder{
View rowView;
TextView itemPID;
TextView itemPrice;
TextView itemItemId;
Spinner spinner;
TextView subtotal;
}
XML:
<Spinner
android:id="@+id/spinner1"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_margin="20dip"
android:entries="@array/quanitiy"
android:layout_alignTop="@+id/itemPrice"
android:layout_toRightOf="@+id/imageDisplay" />
Array:
<string-array name="quanitiy">
<item>Quantity</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
</string-array>
UPDATE
I commented out the code for OnItemClickListner
. I updated the code above, still the problem exists. The only thing left is the declarations.
Scenario:
If I select 1
at the first item of the spinner [index 0] of the ListView
, the last item of ListView
's spinner gets also 1
without interaction. When down the listview's items until the last part, that's where I found out that they are both the same. I commented out the codes and just retained the declarations.
Ok now I got it. Thanks for the clarifications. Your problem comes from views being recycled. You should take a look at this post to understand recycling better.
The short answer
Basically, when you use the
convertView
ingetView()
, you are reusing the view of an item that is no longer visible. That's why its fields (including the spinner, the textview for the price...) are already set to something, and you should set them yourself ingetView()
. The values to give these textfields and the spinner should depend on the item at the specifiedposition
.The detailed answer
Here's what recycling does (picture taken from the post previously mentioned):
Your problem
Here when you scroll to display a new item (let's say item 8, like the picture), the view used to display it is the same as the one for the first item (item 1). Therefore, when you select something on the spinner of the first item, and then scroll down, you will see the change in the last item too because your
getView
doesn't change the values of the views that were used for item 1 (but it is supposed to update them!).Note: The correspondance of the first and the last item in your case is totally by chance. Usually, the view is reused for 2 items that are approximately separated by the number of items in one screen height, as you can see in the picture.
Inline explanation in YOUR code for
getView
The solution
Your not supposed to let the items behave as they please, but you're supposed to tell them what to display when you initialize the item view's content in
getView()
. For the picture above, this means you need to change what used to be item 1 into item 8.You should keep the state of each item in your adapter. You probably have a backing list or something to display different elements in your
ListView
depending on theposition
, right? Then you should use a similar list (or the same) to store the value selected in the spinner, the value displayed by the text field for the price etc. These should probably correspond to fields of the items in your current list anyway, so you probably already have some place to store them.On the other hand, when you reuse the
convertView
ingetView()
, ensure you initialize the spinner (and text field, and everything in this item view) with the correct values for the item atposition
.Solution code (template) for
getView