Saturday, February 26, 2011

Re: [android-developers] listview checkbox recycle issue

ViewHolder is not a good place to store data state - as you are doing.

A ViewHolder is not associated with the data item, it's associated with
the item layout, and when recycling happens, the view holder is also
affected.

You need to store selection state in MyObject, so it's completely
separate from the list item views. With that done, you'll be able to
count on selection state being correct when updating the UI (the check
box). Make sure to update selection state in an appropriate MyObject
based on user actions.

-- Kostya

26.02.2011 5:00, Wall-E пишет:
> I have a ListActivity and an ArrayAdapter that contains a list of an
> Object for example ArrayAdapter<MyObject>. Now in my ArrayAdapter I
> inflate a layout that includes a checkbox. I'm having the issue now
> that when I click on the checkboxes it's fine until it scrolls past
> the window. Now I know that the adapter recycles views so let me
> explain how I have my adapter set up and if anyone could kindly see
> what I'm doing wrong:
>
> I have a ViewHolder class such as the following:
>
> public class ViewHolder
> {
> View base;
> CheckBox checkbox;
> TextView tagTexView;
> TextView tagIDTextView;
>
> public ViewHolder(View base)
> {
> this.base = base;
> }
>
> CheckBox getTagCheckBox()
> {
> if(checkbox == null)
> {
> checkbox = (CheckBox) base.findViewById(R.id.tagInfoCheckBox);
> }
> return checkbox;
> }
>
> TextView getTagMainIdentifierTextView()
> {
> if(tagTexView == null)
> {
> TwoLineListItem twoListItem = (TwoLineListItem)
> base.findViewById(R.id.taginfo_layoutTwoLineListItem);
> tagTexView = (TextView) twoListItem.getText1();
> }
> return tagTexView;
> }
>
> TextView getTagIDTextView()
> {
> if(tagIDTextView == null)
> {
> TwoLineListItem twoListItem = (TwoLineListItem)
> base.findViewById(R.id.taginfo_layoutTwoLineListItem);
> tagIDTextView = (TextView) twoListItem.getText2();
> }
> return tagIDTextView;
> }
> }
>
> Now in my getView method, I inflate convertView and create the
> viewHolder if convertView is null or set the view holder if it's not
> (holder = (ViewHolder) convertView.getTag()).
>
> After that, I set all the values of the views by accessing the views
> using the holder, for example:
>
> holder.getTagCheckBox().setChecked(tag.plot);
>
> where tag is MyObject that I get using getItem(position) inside my
> getView and tag.plot is the boolean value that will indicate if the
> checkbox should be checked or not.
>
> I also created a OnCheckedChangeListener that just sets to tag.plot to
> whatever the checked state is and then call notifyDataSetChanged();
>
> So the text that I update in my views works just fine but the checkbox
> seems to get screwed up and although I've read a few suggestions, none
> of them have worked.
>
> @Override
> public View getView(final int position, View convertView, ViewGroup
> parent)
> {
> mInflater = LayoutInflater.from(context);
>
> final MyObject tag = this.getItem(position);
>
> // A ViewHolder keeps references to children views to avoid
> // unneccessary calls to findViewById() on each row.
> ViewHolder holder;
>
> // When convertView is not null, we can reuse it directly, there is
> // no need to reinflate it. We only inflate a new View when the
> convertView
> // supplied by ListView is null.
> if (convertView == null)
> {
> convertView = mInflater.inflate(R.layout.taginfo_layout, null);
>
> // Creates a ViewHolder and store references to the two children
> // views we want to bind data to.
> holder = new ViewHolder(convertView);
>
> convertView.setTag(holder);
> }
> else
> {
> // Get the ViewHolder back to get fast access to the TextView
> // and the ImageView.
> holder = (ViewHolder) convertView.getTag();
> }
>
> // Set the checkbox value to the value of tag.plot
> holder.getTagCheckBox().setChecked(tag.plot);
> holder.getTagCheckBox().setOnCheckedChangeListener(new
> android.widget.CompoundButton.OnCheckedChangeListener()
> {
> @Override
> public void onCheckedChanged(CompoundButton buttonView,
> boolean isChecked)
> {
> tag.plot = isChecked;
> notifyDataSetChanged();
> }
>
> });
>
> // just for testing I print out the position of the
> view
> holder.getTagMainIdentifierTextView().setText("Position: " +
> position);
>
> holder.getTagIDTextView().setText("Tag ID: " + tagid);
>
> return convertView;
> }
>
> If anyone could find what my mistake is in terms of handling the
> checkbox, I would greatly appreciate it. Also let me know if I need
> to post more code.
>


--
Kostya Vasilyev -- http://kmansoft.wordpress.com

--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

No comments:

Post a Comment