Search code examples
javaandroidlistviewbaseadapterandroid-filterable

Searching not working in custom list view


I have referred to this , this also and this one too. No where I am finding the solution of my problem. On typing in edit text No filtering is there and list view remains as it is Here is the code:

MainActivity.java

public class MainActivity extends AppCompatActivity implements OnItemClickListener {

public static final String[] titles = new String[] { "H C Verma",
        "P Bahadur", "I E Irodov", "M L Khanna",
        "O P Tondon", "Morrison & Boyd", "Halliday Resnick",
        "R D Sharma", "S L Loney", "Hall and Knight", "Krotov", "I A Maron" };
public EditText search;
CustomAdapter adapter;

public static final String[] descriptions = new String[] {

        "Physics",
        "Chemistry",
        "Physics",
        "Mathematics",
        "Chemistry",
        "Chemistry",
        "Physics",
        "Mathematics",
        "Mathematics",
        "Chemistry",
        "Physics",
        "Mathematics"

};

public static final Integer[] images = { R.drawable.hcv,
    R.drawable.bahadur, R.drawable.irodov, R.drawable.mlkhanna,
    R.drawable.tondon, R.drawable.boyd, R.drawable.resnick, R.drawable.sharma,
    R.drawable.loney, R.drawable.knight, R.drawable.krotov, R.drawable.maron};
public static final String[] pub = new String[]{"Bharti Bhavan", "G R Bathla Publications", "Arihant",
"Jai Prakash Nath", "G R Bathla Publications", "Pearson Publications",
"Wiley Publications", "Dhanpat Rai Publications","Classic Texts series","Classic Texts series","G K Publications","G K Publications"};

ListView listView;
List<RowItem> rowItems;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    search = (EditText)findViewById(R.id.inputSearch);

    rowItems = new ArrayList<>();
    for (int i = 0; i < titles.length; i++) {
        RowItem item = new RowItem(images[i], titles[i], descriptions[i], pub[i]);
        rowItems.add(item);
    }

    listView = (ListView) findViewById(R.id.list);
    adapter = new CustomAdapter(this, rowItems);
    listView.setAdapter(adapter);
    listView.setOnItemClickListener(this);
    listView.setTextFilterEnabled(true);

    search.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
           System.out.println("Text ["+s+"]");

            adapter.getFilter().filter(s.toString());

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
                        long id) {
    Toast toast = Toast.makeText(getApplicationContext(),
            "Item " + (position + 1) + ": " + rowItems.get(position),
            Toast.LENGTH_SHORT);
    toast.show();
}

}

CustomAdapter.java

public class CustomAdapter extends BaseAdapter implements Filterable{
List<RowItem> filteredData;
Context context;
List<RowItem> rowItems;
CustomFilter filter;

public CustomAdapter(Context context, List<RowItem> items) {
    this.context = context;
    this.rowItems = items;
    this.filteredData = items;
}
@Override
public int getCount() {
    return filteredData.size();
}

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

@Override
public long getItemId(int position) {
    return rowItems.indexOf(getItem(position));
}



/*private view holder class*/
private class ViewHolder {
    ImageView imageView;
    TextView txtTitle;
    TextView txtDesc;
    TextView pubname;
}

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;

    LayoutInflater mInflater = (LayoutInflater)
            context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, parent, false);
        holder = new ViewHolder();
        holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
        holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
        holder.pubname = (TextView) convertView.findViewById(R.id.pub);
        holder.imageView = (ImageView) convertView.findViewById(R.id.icon);
        convertView.setTag(holder);
    }
    else {
        holder = (ViewHolder) convertView.getTag();
    }

    RowItem rowItem = (RowItem) getItem(position);

    holder.txtDesc.setText(rowItem.getDesc());
    holder.txtTitle.setText(rowItem.getTitle());
    holder.pubname.setText(rowItem.getPub());
    holder.imageView.setImageResource(rowItem.getImageId());

    return convertView;
}
public Filter getFilter() {
    if(filter == null)
    {
        filter=new CustomFilter();
    }

    return filter;}


  class CustomFilter extends Filter {
      @Override
      protected FilterResults performFiltering(CharSequence constraint) {

          FilterResults results = new FilterResults();

          if (constraint != null && constraint.length() > 0) {
              //CONSTARINT TO UPPER
              constraint = constraint.toString().toUpperCase();

              ArrayList<RowItem> filters = new ArrayList<RowItem>();

              //get specific items
              for (int i = 0; i < filteredData.size(); i++) {
                  if (filteredData.get(i).getTitle().toUpperCase().contains(constraint)) {
                      RowItem p = new RowItem(filteredData.get(i).getImageId(), filteredData.get(i).getTitle(), filteredData.get(i).getDesc(), filteredData.get(i).getPub());

                      filters.add(p);
                  }
              }

              results.count = filters.size();
              results.values = filters;

          } else {
              results.count = filteredData.size();
              results.values = filteredData;

          }

          return results;
      }
      @SuppressWarnings("unchecked")
      @Override
      protected void publishResults(CharSequence constraint, FilterResults results) {
          // TODO Auto-generated method stub

          if (results.count == 0) {
              notifyDataSetInvalidated();
          } else {
              rowItems = (ArrayList<RowItem>) results.values;
              notifyDataSetChanged();
          }
      }

  }}

content_main.xml

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginTop="35dp"
    android:orientation="vertical" >
<EditText android:id="@+id/inputSearch"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="45dp"
    android:hint="Search Books.."
    android:inputType="textVisiblePassword"/>

<ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:padding="20dip"
        android:listSelector="@drawable/list_selector"
        />

</LinearLayout>

Please help me out.

using ArrayAdapter

public class CustomAdapter extends ArrayAdapter<RowItem> implements Filterable{
List<RowItem> filteredData;
Context context;
List<RowItem> rowItems;
CustomFilter filter;

public CustomAdapter(Context context, List<RowItem> items) {
    super(context, R.layout.list_item);
    this.context = context;
    this.rowItems = items;
    this.filteredData = items;
}
 /* @Override
public int getCount() {
    return filteredData.size();
}

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

@Override
public long getItemId(int position) {
    return rowItems.indexOf(getItem(position));
}*/



/*private view holder class*/
private class ViewHolder {
    ImageView imageView;
    TextView txtTitle;
    TextView txtDesc;
    TextView pubname;
}

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;

    LayoutInflater mInflater = (LayoutInflater)
            context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, parent, false);
        holder = new ViewHolder();
        holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
        holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
        holder.pubname = (TextView) convertView.findViewById(R.id.pub);
        holder.imageView = (ImageView) convertView.findViewById(R.id.icon);
        convertView.setTag(holder);
    }
    else {
        holder = (ViewHolder) convertView.getTag();
    }

    RowItem rowItem = (RowItem) getItem(position);

    holder.txtDesc.setText(rowItem.getDesc());
    holder.txtTitle.setText(rowItem.getTitle());
    holder.pubname.setText(rowItem.getPub());
    holder.imageView.setImageResource(rowItem.getImageId());

    return convertView;
}
public Filter getFilter() {
    if(filter == null)
    {
        filter=new CustomFilter();
    }

    return filter;}


  class CustomFilter extends Filter {
      @Override
      protected FilterResults performFiltering(CharSequence constraint) {

          FilterResults results = new FilterResults();

          if (constraint != null && constraint.length() > 0) {
              //CONSTARINT TO UPPER
              constraint = constraint.toString().toUpperCase();

              ArrayList<RowItem> filters = new ArrayList<RowItem>();

              //get specific items
              for (int i = 0; i < filteredData.size(); i++) {
                  if (filteredData.get(i).getTitle().toUpperCase().contains(constraint)) {
                      RowItem p = new RowItem(filteredData.get(i).getImageId(), filteredData.get(i).getTitle(), filteredData.get(i).getDesc(), filteredData.get(i).getPub());

                      filters.add(p);
                  }
              }

              results.count = filters.size();
              results.values = filters;

          } else {
              results.count = filteredData.size();
              results.values = filteredData;

          }

          return results;
      }
      @SuppressWarnings("unchecked")
      @Override
      protected void publishResults(CharSequence constraint, FilterResults results) {
          // TODO Auto-generated method stub

          if (results.count == 0) {
              notifyDataSetInvalidated();
          } else {
              rowItems = (ArrayList<RowItem>) results.values;
              notifyDataSetChanged();
          }
      }

  }

Solution

  • Ok so! The two silly mistakes done in the code is: In CustomAdapter.java which is extending base class replace

     rowItems = (ArrayList<RowItem>) results.values;
    

    with

     filteredData = (ArrayList<RowItem>) results.values;
    

    and since on erasing the text entered in edit text also leads to textchange function being called and hence if filteredData is again searched than it will search only out of previously filtered data, so add

    filteredData = rowItems;
    

    just before

     FilterResults results = new FilterResults();
    

    Thank you.