title: Working with CheckBox in ListView and Filterable on Android
body: <p>From this tutorial (<a href="http://www.tutorialsbuzz.com/2014/08/filter-custom-listviewbaseadapter.html" rel="nofollow">http://www.tutorialsbuzz.com/2014/08/filter-custom-listviewbaseadapter.html</a>), I am able to filter items in <code>ListView</code> according to <code>EditText</code> input:</p>
  
  <p>The result works perfectly as expected. However when I try to put <code>CheckBox</code> in <code>ListView</code> item, things get a little out of hand. Below are my modification of source code from the tutorial.</p>
  
  <p><strong>Country.java</strong></p>
  
  <pre><code>public class Country {
  
      String name;
      String iso_code;
      int flag;
      Boolean checked;
  
      Country(String name, String iso_code, int flag, Boolean checked) {
          this.name = name;
          this.iso_code = iso_code;
          this.flag = flag;
          this.checked = checked;
      }
  
      public String getIso_code() {
          return iso_code;
      }
  
      public void setIso_code(String iso_code) {
          this.iso_code = iso_code;
      }
  
      public String getName() {
          return name;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  
      public int getFlag() {
          return flag;
      }
  
      public void setFlag(int flag) {
          this.flag = flag;
      }
  
      public Boolean getChecked() {
          return checked;
      }
  
      public void setChecked(Boolean checked) {
          this.checked = checked;
      }
  }
  </code></pre>
  
  <p><strong>list_item.xml</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;RelativeLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:padding="2dp"&gt;
  
      &lt;ImageView
          android:id="@+id/flag"
          android:layout_width="80dp"
          android:layout_height="70dp"
          android:paddingLeft="10dp"
          android:paddingRight="10dp"/&gt;
  
      &lt;TextView
          android:id="@+id/name"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginLeft="10dp"
          android:layout_marginTop="10dp"
          android:layout_toRightOf="@+id/flag"
          android:paddingBottom="10dp"
          android:text="txt"
          android:textColor="#000000"
          android:textSize="20sp"/&gt;
  
      &lt;TextView
          android:id="@+id/code"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignLeft="@+id/name"
          android:layout_below="@+id/name"
          android:layout_marginLeft="5dp"
          android:text="txt"
          android:textColor="#000000"
          android:textSize="16sp"/&gt;
  
      &lt;CheckBox
          android:id="@+id/checkBox"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentRight="true"
          android:layout_centerVertical="true"
          android:layout_marginRight="16dp"/&gt;
  
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p><strong>CustomAdapter.java</strong></p>
  
  <pre><code>public class CustomAdapter extends BaseAdapter implements Filterable {
  
      Context context;
      ArrayList&lt;Country&gt; countrylist;
      ArrayList&lt;Country&gt; mStringFilterList;
      ValueFilter valueFilter;
  
      CustomAdapter(Context context , ArrayList&lt;Country&gt; countrylist) {
          this.context = context;
          this.countrylist = countrylist;
          mStringFilterList = countrylist;
      }
  
      @Override
      public int getCount() {
          return countrylist.size();
      }
  
      @Override
      public Object getItem(int position) {
          return countrylist.get(position);
      }
  
      @Override
      public long getItemId(int position) {
          return countrylist.indexOf(getItem(position));
      }
  
      @Override
      public View getView(int position , View convertView , ViewGroup parent ) {
  
          LayoutInflater mInflater = (LayoutInflater) context
                  .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
  
          convertView = null;
          if (convertView == null) {
              convertView = mInflater.inflate(R.layout.list_item, null);
  
              TextView name_tv = (TextView) convertView.findViewById(R.id.name);
              TextView iso_tv = (TextView) convertView.findViewById(R.id.code);
              ImageView iv = (ImageView) convertView.findViewById(R.id.flag);
              CheckBox cb = (CheckBox) convertView.findViewById(R.id.checkBox);
  
              Country country = countrylist.get(position);
  
              name_tv.setText(country.getName());
              iso_tv.setText(country.getIso_code());
              iv.setImageResource(country.getFlag());
  
              cb.setChecked(country.getChecked());
              cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {    @Override
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
          country.setChecked(isChecked);
      }
  });
  
  
          }
          return convertView;
      }
  
      @Override
      public Filter getFilter() {
          if (valueFilter == null) {
              valueFilter = new ValueFilter();
          }
          return valueFilter;
      }
  
      private class ValueFilter extends Filter {
          @Override
          protected FilterResults performFiltering(CharSequence constraint) {
              FilterResults results = new FilterResults();
  
              if (constraint != null &amp;&amp; constraint.length() &gt; 0) {
                  ArrayList&lt;Country&gt; filterList = new ArrayList&lt;Country&gt;();
                  for (int i = 0; i &lt; mStringFilterList.size(); i++) {
                      if ( (mStringFilterList.get(i).getName().toUpperCase() )
                              .contains(constraint.toString().toUpperCase())) {
  
                          Country country = new Country(mStringFilterList.get(i)
                                  .getName() ,  mStringFilterList.get(i)
                                  .getIso_code() ,  mStringFilterList.get(i)
                                  .getFlag());
  
                          filterList.add(country);
                      }
                  }
                  results.count = filterList.size();
                  results.values = filterList;
              } else {
                  results.count = mStringFilterList.size();
                  results.values = mStringFilterList;
              }
              return results;
          }
  
          @Override
          protected void publishResults(CharSequence constraint,
                  FilterResults results) {
              countrylist = (ArrayList&lt;Country&gt;) results.values;
              notifyDataSetChanged();
          }
      }
  }
  </code></pre>
  
  <p>When being filtered, the state of <code>CheckBox</code> jumps almost always randomly. I assume because the value of checked in <code>Country</code> changes upon in runtime. Any idea how to implement this in correct way?</p>