31

I am new to Android development. I created a listview with a textbox and checkbox.

When I check the checkbox and scroll it down to check some other items in the list view, the older ones are unchecked.

How do I avoid this problem in a listview? Please guide me with my code.

Here is the code:

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView
        android:id="@+id/TextView01"
        android:layout_height="wrap_content"
        android:text="List of items"
        android:textStyle="normal|bold"
        android:gravity="center_vertical|center_horizontal"
        android:layout_width="fill_parent"/>

    <ListView
        android:id="@+id/ListView01"
        android:layout_height="250px"
        android:layout_width="fill_parent"/>

    <Button
        android:text="Save"
        android:id="@+id/btnSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

This is the XML page I used to create dynamic list row:

listview.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:gravity="left|center"
    android:layout_width="wrap_content"
    android:paddingBottom="5px"
    android:paddingTop="5px"
    android:paddingLeft="5px">

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="#FFFF00"
        android:text="hi"/>

    <TextView
        android:text="hello"
        android:id="@+id/TextView02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10px"
        android:textColor="#0099CC"/>

    <EditText
        android:id="@+id/txtbox"
        android:layout_width="120px"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:layout_x="211px"
        android:layout_y="13px"/>

    <CheckBox
        android:id="@+id/chkbox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

This is my activity class.

CustomListViewActivity.java:

public class CustomListViewActivity extends Activity {

    ListView lstView;
    static Context mContext;
    Button btnSave;

    private static class EfficientAdapter extends BaseAdapter {
        private LayoutInflater mInflater;

        public EfficientAdapter(Context context) {
            mInflater = LayoutInflater.from(context);

        }

        public int getCount() {
            return country.length;
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            final ViewHolder holder;
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.listview, parent,
                        false);
                holder = new ViewHolder();
                holder.text = (TextView) convertView
                        .findViewById(R.id.TextView01);
                holder.text2 = (TextView) convertView
                        .findViewById(R.id.TextView02);
                holder.txt = (EditText) convertView.findViewById(R.id.txtbox);
                holder.cbox = (CheckBox) convertView.findViewById(R.id.chkbox1);

                convertView.setTag(holder);
            }
            else {
                holder = (ViewHolder) convertView.getTag();
            }

            holder.text.setText(curr[position]);
            holder.text2.setText(country[position]);
            holder.txt.setText("");
            holder.cbox.setChecked(false);

            return convertView;
        }

        public class ViewHolder {
            TextView text;
            TextView text2;
            EditText txt;
            CheckBox cbox;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lstView = (ListView) findViewById(R.id.ListView01);
        lstView.setAdapter(new EfficientAdapter(this));
        btnSave = (Button)findViewById(R.id.btnSave);
        mContext = this;

        btnSave.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // I want to print the text which is in the listview one by one.
                // Later I will insert it in the database.
                //
                //            Toast.makeText(getBaseContext(), "EditText Value, checkbox value and other values", Toast.LENGTH_SHORT).show();
                for (int i = 0; i < lstView.getCount(); i++) {
                    View listOrderView;
                    listOrderView = lstView.getChildAt(i);
                    try{
                        EditText txtAmt = (EditText)listOrderView.findViewById(R.id.txtbox);
                        CheckBox cbValue = (CheckBox)listOrderView.findViewById(R.id.chkbox1);
                        if(cbValue.isChecked()== true){
                            String amt = txtAmt.getText().toString();
                            Toast.makeText(getBaseContext(), "Amount is :"+amt, Toast.LENGTH_SHORT).show();
                        }

                    }
                    catch (Exception e) {
                        // TODO: handle exception
                    }
                }

            }
        });
    }

    private static final String[] country = { "item1", "item2", "item3",
        "item4", "item5", "item6","item7", "item8", "item9",
        "item10", "item11", "item12" };

    private static final String[] curr = { "1", "2", "3", "4", "5", "6","7", "8", "9", "10", "11", "12" };
}

Please help me to solve this problem.

I have referred to this problem in many places. But I could not get proper answer to solve this problem.

Please provide me the code to avoid unchecking the checkbox while scrolling up and down.

Community
  • 1
  • 1
Mathew
  • 565
  • 2
  • 7
  • 16

9 Answers9

37

In the custom listview adapter call setChecked after calling setOnCheckedChangeListener.

This way you sever the link to the old listener from the recycled view.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
varotariya vajsi
  • 3,965
  • 37
  • 39
  • 1
    I know this is very old but can you please elaborate bit more? `setChecked` with what parameter. I called with `false` and after scroll it gets unchecked. Do we need to maintain array of selections here or what. – Atul Apr 22 '17 at 10:40
  • Hello @Atul , there are lots of ways to maintain listview with checkbox, you can use array or better way to use sparsebooleanarray, You can also refer this http://lalit3686.blogspot.in/2012/06/today-i-am-going-to-show-how-to-deal.html. Thank you...!!! – varotariya vajsi Apr 22 '17 at 10:52
  • Ok. I got it. We need to maintain flags and call `setChecked` from same. Btw this answer contradicts to [this](http://stackoverflow.com/a/35554898/1911652) which says we should call `setChecked` **before** we call `setOnCheckedChangeListener` – Atul Apr 22 '17 at 10:53
  • About calling sequence this is correct approach: http://stackoverflow.com/a/15523518/1911652 – Atul Apr 22 '17 at 11:06
  • Yup, this one is great answer given by @Shade – varotariya vajsi Apr 22 '17 at 11:33
  • Re *"sever the link"*: Do you mean *"serve the link"*? – Peter Mortensen Aug 04 '17 at 17:38
6

You can use the following adapter code to run a checkbox perfectly in a ListView.

A detailed demo is here: Listview With Checkbox Android

See the detailed demo link for deep information. It also shows how to send checked information to the next activity.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;


public class CustomAdapter  extends BaseAdapter {

    private Context context;
    public static ArrayList<Model> modelArrayList;

    public CustomAdapter(Context context, ArrayList<Model> modelArrayList) {

        this.context = context;
        this.modelArrayList = modelArrayList;
    }

    @Override
    public int getViewTypeCount() {
        return getCount();
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    @Override
    public int getCount() {
        return modelArrayList.size();
    }

    @Override
    public Object getItem(int position) {
        return modelArrayList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;

        if (convertView == null) {
            holder = new ViewHolder(); LayoutInflater inflater = (LayoutInflater) context
                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.lv_item, null, true);

            holder.checkBox = (CheckBox) convertView.findViewById(R.id.cb);
            holder.tvAnimal = (TextView) convertView.findViewById(R.id.animal);

            convertView.setTag(holder);
        }
        else {
            // The getTag returns the viewHolder object set as a tag to the view
            holder = (ViewHolder)convertView.getTag();
        }

        holder.checkBox.setText("Checkbox " + position);
        holder.tvAnimal.setText(modelArrayList.get(position).getAnimal());

        holder.checkBox.setChecked(modelArrayList.get(position).getSelected());

        holder.checkBox.setTag(R.integer.btnplusview, convertView);
        holder.checkBox.setTag( position);
        holder.checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                View tempview = (View) holder.checkBox.getTag(R.integer.btnplusview);
                TextView tv = (TextView) tempview.findViewById(R.id.animal);
                Integer pos = (Integer)  holder.checkBox.getTag();
                Toast.makeText(context, "Checkbox " + pos + " clicked!", Toast.LENGTH_SHORT).show();

                if (modelArrayList.get(pos).getSelected()){
                    modelArrayList.get(pos).setSelected(false);
                }
                else {
                    modelArrayList.get(pos).setSelected(true);
                }

            }
        });

        return convertView;
    }

    private class ViewHolder {

        protected CheckBox checkBox;
        private TextView tvAnimal;
    }
}

Model is

public class Model {

    private boolean isSelected;

    private String animal;

    public String getAnimal() {
        return animal;
    }

    public void setAnimal(String animal) {
        this.animal = animal;
    }

    public boolean getSelected() {
        return isSelected;
    }

    public void setSelected(boolean selected) {
        isSelected = selected;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user6017633
  • 483
  • 7
  • 9
3

In your getView() you have the following line

holder.cbox.setChecked(false);

which sets CheckBox unchecked every time getView() is called (when you scroll your list, for example)

Vladimir
  • 9,683
  • 6
  • 36
  • 57
  • 1
    Hi Vladimir, Thank you for your sugession. I remove this line and run it. It did not uncheck the checkbox this time. But When i select first and second item in the list and scroll, some other items are selected automatically. I think it refers to the position of the list and check it automatically when i scroll it up and down. How to solve this? – Mathew Jun 05 '12 at 11:23
  • 1
    `getView()` reuses the `convertView`, so if CheckBox was checked in some position it will remain checked when it's reused. You need to find a way to set it's checked status according to some condition – Vladimir Jun 05 '12 at 11:31
1

Blockquote

**In Side getView() Method just call like this>>

check.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton arg0, boolean arg1) 
            {

                if(check.isChecked())
                {
                    //checked
                    chkArray[position]=true;
                }
                else
                {   //uncheck
                  chkArray[position]=false;

                }
            }
        });

//check condition for checkboxes
        if(chkArray.length>0)
        {
            for (int i = 0; i < chkArray.length; i++) 
            {
                if(chkArray[position]!=null && chkArray[position])
                {
                    check.setChecked(true);
                }
            }
        }
ranjan
  • 136
  • 1
  • 12
0

Consider:

holder.cbox.setChecked(false);

Remove this line. When you scrolled the list view every time, the getView() method is called.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bhargav Panchal
  • 1,159
  • 1
  • 12
  • 27
  • Hi Panchal, Thank you for your reply. I remove this line and run it. It did not uncheck the checkbox this time. But When i select first and second item in the list and scroll, some other items are selected automatically. I think it refers to the position of the list and check it automatically when i scroll it up and down. – Mathew Jun 05 '12 at 11:22
0

I also got this problem before. Android does this to save space; only the items you currently see are loaded, and this is what I found out.

If you are on the bottom on your list, the id 1 is on maybe position 5. I searched on the web and found this out before.

But this will help you :D

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Boe-Dev
  • 1,585
  • 2
  • 14
  • 26
0

finally i have reached to the solution few hours later that is by

  1. add a Boolean variable array class with set and get methods.
  2. add an array to save my selections in it.
  3. use onClickListner.

inside getView method as the following:


if(marray!=null) { //if myarray class object has data
holder.name.setText(marray.getName());
.
.
holder.checkbox.setChecked(marray.isChecked());//get the checkbox state 
}

give the value to the boolean variable in holder.checkbox.setOnClickListener method as:


holder.checkbox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (allReport.UserSelection.contains(
Integer.parseInt(marrays.get(position)
.getIdd()))) // check if id selected before
                    {
      marray.setChecked(false);// marray is the object from myArray class
      allReport.UserSelection.remove(new Integer(Integer.parseInt(marrays.get(position).getIdd())));//remove id 


 }else{
       allReport.UserSelection.add(Integer.parseInt
           (marrays.get(position).getIdd()));//save the selection 
            marray.setChecked(true);//save the boolean to true}

that's solve the problem for me i hope that's make any help

0

Its solution is to add itemView.OnClicklistener changes in adapter viewholder. This will definately solve your position issue

ahuja
  • 1
  • 1
-1

When we scroll items in listview it restores the value from adapter. That is why the checkbox unchecked. But if we update the adapter with latest value, it will remain checked. For that you need to use setOnClickListener().

All you need to do is update your adapter on checkbox click.You can refer to this link to get an idea

Ricky
  • 135
  • 1
  • 8
  • 1
    avoid link only answers, please explain how this answer is worth trusting. – this.girish May 25 '17 at 06:15
  • When we scroll items in listview it restores the value from adapter. That is why the checkbox unchecked. But if we update the adapter with latest value, it will remain checked. For that you need to use setOnClickListener() – Ricky May 25 '17 at 10:19
  • great, put above explanation as an answer, might help someone in future. – this.girish May 25 '17 at 12:05