Android development blog
Tutorials about Android dev topics

Android ListView : Custom Filter and Filterable interface

In the previous post we showed the way we can programming a custom adapter and a custom layout. One aspect we didn’t cover by now, is how we can filter the items in the ListView. In this post we describe how we can filter items inside a ListView while the user writes words inside an input field. We can use the example shown in the last post and modify it. What do we need to do it?
  • Modify the custom adapter, PlanetAdapter so that it will be able to filter the items
  • Add an input field where the user can insert the keys to filter the ListView
Let’s start then.

Modify the custom adapter so that it implements the Filterable interface

If we didn’t use a custom adapter with custom object inside the ListView, the things would be much easier. For example if we used just String as item content we simply could add a few lines of code to make our list filterable; but we have a custom layout that uses not a simply String but a complex object (i.e. Planet). So we need first modify our custom adapter (PlanetAdapter) so that it implements the android.widget.Filter interface. This interface requires we implement just only one method called getFilter() that returns a android.widget.Filter object. The problem is the way we can create this filter. Very easy!

private class PlanetFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
          ....
    }

    @Override
    protected void publishResults(CharSequence constraint,FilterResults results) {
        .....
    }
    
}

We create a private class called PlanetFilter that extends the android.widget.Filter. This class has two abstract methods:


  • FilterResults performFiltering(CharSequence constraint) : invoked in worker thread, that has the task to filter the results according to the constraint
  • void publishResults(CharSequence constraint,FilterResults results): that has the task to show the result set created by performingFiltering method

Let’s suppose we want to filter the planet list using the name attribute. In our case, then, the constraint can be the initial letters of the planet name, so that if the planet starts with those letters we show it otherwise we hide it.
@Override
protected FilterResults performFiltering(CharSequence constraint) {
    FilterResults results = new FilterResults();
    // We implement here the filter logic
    if (constraint == null || constraint.length() == 0) {
        // No filter implemented we return all the list
        results.values = planetList;
        results.count = planetList.size();
    }
    else {
        // We perform filtering operation
        List<Planet> nPlanetList = new ArrayList<Planet>();
        
        for (Planet p : planetList) {
            if (p.getName().toUpperCase().startsWith(constraint.toString().toUpperCase()))
                nPlanetList.add(p);
        }
        
        results.values = nPlanetList;
        results.count = nPlanetList.size();

    }
    return results;
}

In this method we have to return a FilterResults that has two static attributes called values and count. Values is a list of values to be shown while count is the number of these values. The first thing we do in this method is to verify if the constraint is null or empty, in this case we don’t have to filter the result and simply
results.values = planetList;
results.count = planetList.size();

In other words all the list. If the constraints aren’t null or empty we simply select the planet with its name starting with the constraint, as shown below.
List<Planet> nPlanetList = new ArrayList<Planet>();

for (Planet p : planetList) {
    if (p.getName().toUpperCase().startsWith(constraint.toString().toUpperCase()))
        nPlanetList.add(p);
}

results.values = nPlanetList;
results.count = nPlanetList.size();
The next step is publishing the result.
@Override
protected void publishResults(CharSequence constraint,
        FilterResults results) {
    
    // Now we have to inform the adapter about the new list filtered
    if (results.count == 0)
        notifyDataSetInvalidated();
    else {
        planetList = (List<Planet>) results.values;
        notifyDataSetChanged();
    }
    
}

We said before that the PlanetAdapter has to implement Filterable interface and it has to implement getFilter() method:
@Override
public Filter getFilter() {
    if (planetFilter == null)
        planetFilter = new PlanetFilter();
    
    return planetFilter;
}

This is code is quite trivial, we simply invalidate the result set if the result list is empty or we notify that the result set is changed.

It is done!….quite done!…We need now adding just an input field where user can insert the keyword to filter the result. The new layout becomes:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="vertical"
    android:focusable="true"
    android:focusableInTouchMode="true">

     <EditText
         android:id="@+id/editTxt"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="5dp"
         android:maxLines="1" />
    
    <ListView android:id="@+id/listView" 
              android:layout_height="match_parent"
              android:layout_width="match_parent"
              android:layout_weight="1"/>
    
    
    <Button android:id="@+id/addBtn"
            android:text="Add planet"
            android:onClick="addPlanet"
            android:layout_weight="0.5"
            android:layout_height="80dp"
            android:layout_width="match_parent"/>

    
</LinearLayout>
In the main activity we have to add some listener attached to EditText so that when user writes inside it we can filter the list items.
editTxt.addTextChangedListener(new TextWatcher() {
 
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        System.out.println("Text ["+s+"]");
        aAdpt.getFilter().filter(s.toString());                            
    }
    
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        
    }
    
    @Override
    public void afterTextChanged(Editable s) {
    }
});

Running the code we have:

     androdi_listview_filter android_listview_filtered_itmes

Tricks


One simple trick we have to use is to make soft keyboard hidden at the app startup. As soon as the app starts the EditText gains the focus and the OS shows the keyboard covering the list items. If we don’t want this we can simply “move” the focus somewhere else:

android:focusable="true"
android:focusableInTouchMode="true"
Source code here

52 comments:

  1. Nice work! I used it on my project, but I found a bug on this code. And it just found now, after I change my project android version to work for 4.0.3
    If I press "a" and delete.. repeat it very fast.. the app closes.. ListView need to be notified, that's the error message. But how to notify it again ? or how to avoid this bug ?

    ReplyDelete
  2. Thanks for you comment. I will try to reproduce this bug and fix it and i will release a new source code version.

    ReplyDelete
  3. I tried to reproduce the error you told me...but even if i tried very fast with "a" and delete it the app didn't crash.
    I used 4.0.3 emulator. The only one bug i found is that the code doesn't show the complete list after you delete the filter in the edit view. This is caused by a mistake in the source code. You should create a copy of the original array showed in the listView and when the filter is empty set the value to this copy array.
    I will update the code.
    If you can repeat the error please send me the stack trace so i can have some clues.

    ReplyDelete
    Replies
    1. Hi, Thanks for ur answer. Well, this bug that u found I already fix some months ago. I fix with this code:

      @Override
      protected void publishResults(CharSequence constraint,
      FilterResults results) {

      planetList = (List) results.values;

      // Now we have to inform the adapter about the new list filtered
      if (results.count == 0)
      notifyDataSetInvalidated();
      else {
      notifyDataSetChanged();
      }

      }


      But I really don't find the bug when I repeat any char and delete fast. The stacktrace is:

      java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(-1, class android.widget.ExpandableListView) with Adapter(class android.widget.ExpandableListConnector)]
      at android.widget.ListView.layoutChildren(ListView.java:1567)
      at android.widget.AbsListView.onLayout(AbsListView.java:1280)
      at android.view.View.layout(View.java:7035)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
      at android.view.View.layout(View.java:7035)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
      at android.view.View.layout(View.java:7035)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
      at android.view.View.layout(View.java:7035)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
      at android.view.View.layout(View.java:7035)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
      at android.view.View.layout(View.java:7035)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
      at android.view.View.layout(View.java:7035)
      at android.view.ViewRoot.performTraversals(ViewRoot.java:1045)
      at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)
      at android.os.Handler.dispatchMessage(Handler.java:99)
      at android.os.Looper.loop(Looper.java:123)
      at android.app.ActivityThread.main(ActivityThread.java:4633)
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:521)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
      at dalvik.system.NativeStart.main(Native Method)


      Ok, I understand the error message, but I tried to notify adapter in others ways but doesnt work. Could I add you in facebook, gtalk or g+. And I could send my codes. My app is https://play.google.com/store/apps/details?id=com.edersonschmidt.portobus you might test this issue in "Bus Lines", you could type any char and delete faster.. I changed the way how I implement this filter. but this error still reproduce. Idk why..

      Thanks in advance.

      Delete
  4. You can find me in g+ with survivingwithandroid. My email add is survivingwithandroid@gmail.com. Btw i downloaded your app and it looks great and i didn't find the error even if i filtered the list in the bus line option very very fast (I'm using Gingerbread). Anyway if you like you can send me the code so i can have an idea more detailed. The error seems caused by the fact you try to update the view from an external thread in that case you should somehow implements something like a queue.
    I'd really like to investigate more about it.

    ReplyDelete
  5. I am using custom list Adapter in code.The listview is having indexbar.I need to show items whose words start with letters entered in searchbox i.e. if item is having 3 words and second word start with A and we enter A in searchbox then that item also should get searched.

    ReplyDelete
  6. Well in this case you should replate startsWith with indexOf and verify that that letter is present so indexOf result is != -1

    ReplyDelete
  7. Hi ;
    I tried this code but I had an empty result when I wrote a character and I dont know why

    ReplyDelete
    Replies
    1. The filter works comparing the first letter so if you entered a letter that doens't match any items the result is empty.
      In a few hours i will add to github the entire source code so if you are patient you can try again.

      Delete
    2. Ok; Thank you very much.

      But the letter that I wrote is the first letter of a name of a "Station" in the data base

      This is the code source :

      private class gareFilter extends Filter
      {


      @Override
      protected FilterResults performFiltering(CharSequence constraint) {
      FilterResults results = new FilterResults();
      // We implement here the filter logic
      if (constraint == null || constraint.length() == 0) {
      // No filter implemented we return all the list
      results.values = item_com_list;
      results.count = item_com_list.size();
      }
      else {
      // We perform filtering operation
      List ngaretList = new ArrayList();

      for (gare p : item_com_list) {
      if (p.getNAME().toUpperCase().startsWith(constraint.toString().toUpperCase()))
      ngaretList.add(p);
      }

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

      }
      return results;

      }



      @Override
      protected void publishResults(CharSequence constraint, FilterResults results) {

      item_com_list = (List) results.values;

      // Now we have to inform the adapter about the new list filtered
      if (results.count == 0)
      notifyDataSetInvalidated();
      else {
      notifyDataSetChanged();
      }
      }

      Delete
    3. public void afficher_liste_gares(){


      if(results!=null && results.size() > 0)
      {

      final item_com_Choice adapter=new item_com_Choice(gare_choix_depart_activity.this, results);
      list4.setAdapter(adapter);
      //Teliste_vide_label.setVisibility(View.INVISIBLE);
      list4.setVisibility(View.VISIBLE);
      list4.setTextFilterEnabled(true);
      filterText.addTextChangedListener(new TextWatcher() {

      @Override
      public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) {
      // TODO Auto-generated method stub
      System.out.println("Text ["+s+"]");
      adapter.getFilter().filter(s.toString());

      }

      @Override
      public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
      int arg3) {
      // TODO Auto-generated method stub

      }

      @Override
      public void afterTextChanged(Editable arg0) {
      // TODO Auto-generated method stub

      }
      });

      Delete
  8. In the else part in the publish method you've to replace your code with:
    else {
    planetList = (List) results.values;
    notifyDataSetChanged();
    }
    and remove it from the method.

    ReplyDelete
    Replies
    1. That still not working...I also override the toString method in the class "gare"...but it still not working :(

      @Override
      protected void publishResults(CharSequence constraint, FilterResults results) {

      item_com_list = (List) results.values;

      //Now we have to inform the adapter about the new list filtered
      if (results.count == 0)
      notifyDataSetInvalidated();
      else {
      item_com_list = (List) results.values;
      notifyDataSetChanged();

      }

      Delete
    2. Thanks a lot ,but it still not working,when I write a letter in the EditText nothing happens...and I dont know why :(

      Delete
    3. public class item_com_Choice extends ArrayAdapter implements Filterable {

      private List planetList;
      private Context context;
      private Filter planetFilter;
      private List origPlanetList;

      public item_com_Choice(Context ctx,List planetList ) {
      super(ctx, R.layout.item4, planetList);
      this.planetList = planetList;
      this.context = ctx;
      this.origPlanetList = planetList;
      }
      @Override
      public int getCount() {
      return planetList.size();
      }
      @Override
      public gare getItem(int position) {
      return planetList.get(position);
      }
      @Override
      public long getItemId(int position) {
      return planetList.get(position).hashCode();
      }
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
      View v = convertView;

      PlanetHolder holder = new PlanetHolder();

      // First let's verify the convertView is not null
      if (convertView == null) {
      // This a new view we inflate the new layout
      LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      v = inflater.inflate(R.layout.item4, null);
      // Now we can fill the layout with the right values
      TextView tv = (TextView) v.findViewById(R.id.item_title_gare);
      TextView distView = (TextView) v.findViewById(R.id.item_id);


      holder.planetNameView = tv;
      holder.distView = distView;

      v.setTag(holder);
      }
      else
      holder = (PlanetHolder) v.getTag();

      gare p = planetList.get(position);
      holder.planetNameView.setText(p.getNAME());
      holder.distView.setText("" + p.getCODE());


      return v;
      }



      /* *********************************
      * We use the holder pattern
      * It makes the view faster and avoid finding the component
      * **********************************/

      private static class PlanetHolder {
      public TextView planetNameView;
      public TextView distView;
      }



      /*
      * We create our filter
      */

      @Override
      public Filter getFilter() {
      if (planetFilter == null)
      planetFilter = new PlanetFilter();

      return planetFilter;
      }



      private class PlanetFilter extends Filter {



      @Override
      protected FilterResults performFiltering(CharSequence constraint) {
      FilterResults results = new FilterResults();
      // We implement here the filter logic
      if (constraint == null || constraint.length() == 0) {
      // No filter implemented we return all the list
      results.values = origPlanetList;
      results.count = origPlanetList.size();
      }
      else {
      // We perform filtering operation
      List nPlanetList = new ArrayList();

      for (gare p : planetList) {
      if (p.getNAME().toUpperCase().startsWith(constraint.toString().toUpperCase()))
      nPlanetList.add(p);
      }

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

      }
      return results;
      }

      @SuppressWarnings("unchecked")
      @Override
      protected void publishResults(CharSequence constraint,
      FilterResults results) {

      // Now we have to inform the adapter about the new list filtered
      if (results.count == 0)
      notifyDataSetInvalidated();
      else {
      planetList = (List) results.values;
      notifyDataSetChanged();
      }
      }
      }
      }

      Delete
    4. public void afficher_liste_gares(){


      if(results!=null && results.size() > 0)
      {

      adapter=new item_com_Choice(this, results);
      list4.setAdapter(adapter);
      //Teliste_vide_label.setVisibility(View.INVISIBLE);
      list4.setVisibility(View.VISIBLE);
      list4.setTextFilterEnabled(true);

      filterText.addTextChangedListener(new TextWatcher() {

      @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 beforeTextChanged(CharSequence s, int start, int count,
      int after) {

      }

      @Override
      public void afterTextChanged(Editable s) {
      }
      });


      }
      else
      {
      //Teliste_vide_label.setVisibility(View.VISIBLE);
      list4.setVisibility(View.INVISIBLE);
      list4.setTextFilterEnabled(true);
      }

      }


      In the list I am adding the values from a JSON URL

      Delete
    5. Since you are populating your list using a JSON URL it could be wise to use an async adapter. It could be that your list isnt still populated when you filter it. I suggest to you to try with a "static" items and verify that everything works then you move on and try to populate the list using JSON.
      It could be useful to verify if item ids are stable there's a method to verify it.
      Anyway i will try to set up an example code that populates the list using a JSON and i will verify the result.
      Reading your code it seems everything is fine so the only one thing that is different from my example is the JSON URL.

      Delete
    6. Ok,thank you veru much ,I try with autocompletetextview and that's not working too.

      Delete
  9. Hi, code provided by you has been a great help while working on filtering custom list.

    Could you please also tell how to get back the names in the list as the user deletes characters in the search bar to return to the actual list.

    Any help would be appreciated.

    ReplyDelete
  10. I posted how to solve the problem. Bye

    ReplyDelete
  11. Nice post.Give it up. Thanks for share this article. For more visit:android development

    ReplyDelete
  12. great tutorial..

    ReplyDelete
  13. thanks for this great tutorial but where did you post the solution?

    ReplyDelete
  14. survivingwithandroidMay 3, 2013 at 3:10 PM

    Look here http://www.survivingwithandroid.com/2013/01/android-listview-filterable.html

    ReplyDelete
  15. Great Tutorial. Well explained. I used your code from Github and it filters my list fine. However, when I select a listItem it only shows me the first item in the list [0], even if it that item was filtered out. I am using onListItemClick, where you use onItemClick. I'm populating my list from SQLite database and using Parcelable to send the data from the listview to a detail view. This is a project that's due in next week so a reply would be real nice. Thanks.

    ReplyDelete
  16. survivingwithandroidMay 4, 2013 at 8:01 PM

    If i get correctly when you use a filtered list and select one item of this list you get always the first one. If so i think you are using the original arraylist instead of the filtered array.

    ReplyDelete
  17. Correct. I can't seem to select from the filtered list. Can you recommend a solution or is there a way I can get the source code to you? This is the Activity that uses the list https://github.com/mclhrn/bird-note/blob/master/src/com/example/birdnote/ReferenceGuide.java

    And this is the adapter https://github.com/mclhrn/bird-note/blob/master/src/com/example/birdnote/list/CustomBaseAdapter.java

    Thanks for the reply and hope to hear from you....

    ReplyDelete
  18. survivingwithandroidMay 4, 2013 at 10:41 PM

    Well i noticed two things in onListItemClick:

    1. You shouldn't call super.onList... because you are handling the event by yourself

    2. You get the bird information from original birds list and not from the filtered one. So you should ask to the adapter the new birds array (the filtered one) and then get the bird data from it.

    ReplyDelete
  19. Great, Thanks. I'll give it a go now. This is my first app and I'm just getting used to Android.
    Thanks again and I'll let you know how I got on...

    ReplyDelete
  20. Ciao, ho provato il codice da gitHub e funziona.
    Ma applicandolo al mio progetto, in cui ho implementato una mia versione di "Pianeta", il filtro non funziona.

    Il mio codice per la lista è basato sul custom adapter del tuo esempio "SimpleList".


    Non riesco a capire cosa può essere. In pratica quello che scrivo nell' EditText viene ignorato.

    Ho controllato tutto più volte... Qualche idea?

    Il codice del mio progetto è su https://github.com/dentex/ytdownloader/tree/vers3dev/dentex.youtube.downloader/src/dentex/youtube/downloader

    DashboardListItem.java
    DashboardActivity.java
    DashboardAdapter.java

    ciao e grazie comunque per gli ottimi tutorial.

    ReplyDelete
  21. survivingwithandroidJune 18, 2013 at 9:38 AM

    Adesso provo a scaricare il tuo progetto per vedere se riesco a capire xchè il filtro non va.

    ReplyDelete
  22. Grazie mille! non potevo sperare in niente di meglio.

    ReplyDelete
  23. ho appena constatato che sull'emulatore questa implementazione funziona anche nella mia app, così come l'avevo adattata. Quindi adesso devo cercare di capire perchè non funziona sul dispositivo reale...

    Spero di non averti fatto perdere tempo.

    ReplyDelete
  24. Per la miseria funziona pure sul cellulare!
    Non ho toccato il codice, ho solo disinstallato la versione con la firma di Eclipse del portatile, e installato la versione dal desktop.

    Ieri ho perso una giornata... boh.

    ReplyDelete
  25. survivingwithandroidJune 18, 2013 at 5:09 PM

    Probabilmente non aveva installato il codice corretto. Avevo dato un'occhiata al codice e mi sembrava corretto e non vedevo errori, quindi doveva funzionare! :)

    ReplyDelete
  26. I found a solution on how to refer to the filtered list.

    Before calling any method on a list element, you have to take a reference to the modified list (using the names from the example given on this site):

    Planet currentPlanet = aAdpt.getItem(position);

    where "position" is a parameter from, i.e.:

    public boolean onItemLongClick(AdapterView parent, View view, final int position, long id) { ... }

    ReplyDelete
  27. Ho risolto su come fare riferimento alla lista filtrata.
    (ho risposto alla discussione in basso) :D

    ReplyDelete
  28. Hi

    Thanks a lot for this awesome tutorial.. I have successfully implemented it...

    But one question how do i implement in search widget and not using edit text

    I am going through http://developer.android.com/guide/topics/search/search-dialog.html
    and also made the search widget... but how do i get edit text like id from it because search widget don't have any method as addTextChangedListener i suppose..
    but I am unable to make it through... can you help ?

    ReplyDelete
  29. survivingwithandroidJuly 1, 2013 at 12:35 PM

    I guess the approch is different. I will try to analyze your problem. Thank you

    ReplyDelete
  30. Thanks! pls give me some hint as to how to proceed .. I am really stuck :/

    ReplyDelete
  31. Per avere una lista "vuota" (cioè interamente filtrata) quando si inserisce un carattere con cui nessun elemento inizia, ho cambiato:

    public void publishResults(CharSequence constraint,FilterResults results) {
    if (results.count == 0) {
    notifyDataSetInvalidated();
    } else {
    itemsList = (List) results.values;
    notifyDataSetChanged();
    }
    }

    in:

    public void publishResults(CharSequence constraint,FilterResults results) {
    itemsList = (List) results.values;
    notifyDataSetChanged();
    }

    :)

    ReplyDelete
  32. Hey, nice tutorial. Whenever my list has no matches, and nPlanetList is empty, it shows everything. How can I change it to show nothing?

    ReplyDelete
  33. Thanks you so much!. But, if i want to filter a GridView control, what i have to do?, I´ve tried so many tutorials, but nothing works. :(

    ReplyDelete
  34. thanks fo this tutorial.. i have errors in getview method line: Planet p = planetList.get(position);

    java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2

    ReplyDelete
  35. Listview not updating after filtering..

    @Override
    public Filter getFilter()
    {
    if (filter == null)
    filter = new PkmnNameFilter();

    return filter;
    }
    private class PkmnNameFilter extends Filter
    {

    @SuppressLint("DefaultLocale")
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {

    constraint = constraint.toString().toLowerCase();
    FilterResults result = new FilterResults();
    if(constraint != null && constraint.toString().length() > 0)
    {
    ArrayList filteredItems = new ArrayList();

    for(int i = 0, l = fiems.size(); i < l; i++)
    {
    ItemVO in = fiems.get(i);
    final String value = in.getItemdescription().toLowerCase();

    if (value.startsWith((String) constraint))
    {
    filteredItems.add(in);
    }
    }
    result.count = filteredItems.size();
    result.values = filteredItems;
    }
    else
    {
    synchronized(this)
    {
    result.values = fiems;
    result.count = fiems.size();
    }
    }

    return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint,
    FilterResults results) {

    // itemList.clear();
    // dataAdapter.clear();
    itemiList = (ArrayList)results.values;
    notifyDataSetChanged();
    clear();
    int count=itemiList.size();
    for(int i = 0, l = count; i < l; i++)
    add(itemiList.get(i));
    notifyDataSetInvalidated();
    /*if (itemiList != null && count > 0)
    {
    notifyDataSetChanged();
    }
    else
    {
    notifyDataSetInvalidated();
    }*/

    }

    }

    ReplyDelete
  36. In order to remove filter for original items you could consider the following example:

    http://stackoverflow.com/questions/8678163/list-filter-custom-adapter-dont-give-result

    "mOriginalValues" in the above example is used to store original items.

    ReplyDelete
  37. i had problem after filtering my listview the firstTime, for make it work, i create a supportList like this:

    List mainList= new ArrayList();
    List filteredList= new ArrayList();

    in my Custom CostructorAdapter i did (list is becoming from activity)

    mainList = list;

    filteredList.addAll(list)

    then in my getView method i get my object with

    Object obj = filteredList.get(position)

    and set the label ... ecc ecc

    for make this working you have to ovverride the getCount method

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

    i leaved performFiltering like the tutorial, and then edited the publishResult in this way

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
    // Now we have to inform the adapter about the new list filtered
    if (results.count == 0)
    notifyDataSetInvalidated();
    else {
    filteredList= (List) results.values;
    notifyDataSetChanged();
    }


    Hope could help someone :)

    ReplyDelete
  38. Nice Tutorial!!

    Thank you!

    ReplyDelete

Related Posts with Thumbnails