Okechukwu Eze
Okechukwu Eze

Reputation: 149

Search Functionality to ListView using BaseAdapter not populating List on search

I have been trying to implement a simple search to a listView which I have been able to populate using Volley but all to no avail till date. Thanks to @Dhaval Patel who has been of greet help. But the issue I am having now is that when I search, the ListView refuse to change content thus making the whose search useless in the program

Below is my code:

public class MainActivity extends Activity {

   private ListView mList;
   private List<Movie> movieList = new ArrayList<Movie>();
   EditText inputSearch;


    protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
           setContentView(R.layout.activity_main);

       mList = (ListView) findViewById(R.id.list);
       inputSearch = (EditText) findViewById(R.id.inputSearch);


           adapter = new CustomListAdapter(this, movieList);
           mList.setAdapter(adapter);


        //SEARCH TEXTCHANGE
        inputSearch.addTextChangedListener(new TextWatcher() {

             @Override
             public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                   // When user changed the Text
                  MainActivity.this.adapter.getFilter().filter(cs.toString());
                //FLAGS Cannot resolve method 'getFilter()' here
                }

             @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
             }
          });




    }



}

Also this is the code in my CustomListAdapter class

public class CustomListAdapter extends BaseAdapter {

     private Activity activity;
     private LayoutInflater inflater;
     private List<Movie> movieItems;
     private String[] bgColors;
     private List<String>originalData = null;
     private List<String>filteredData = null;
     private ItemFilter mFilter = new ItemFilter();
        ImageLoader imageLoader = MyApplication.getInstance().getImageLoader();


         public CustomListAdapter(Activity activity, List<Movie> movieItems) {
             this.activity = activity;
             this.movieItems = movieItems;
             bgColors = activity.getApplicationContext().getResources().getStringArray(R.array.movie_serial_bg);
         }
         @Override
         public int getCount() {
                return movieItems.size();
         }

         @Override
        public Object getItem(int location) {
             return movieItems.get(location);
         }

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

         @Override
         public View getView(int position, View convertView, ViewGroup parent) {

            if (inflater == null)
              inflater = (LayoutInflater) activity
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             if (convertView == null)
                convertView = inflater.inflate(R.layout.list_row_image, null);

             if (imageLoader == null)
              imageLoader = MyApplication.getInstance().getImageLoader();
            NetworkImageView thumbNail = (NetworkImageView) convertView.findViewById(R.id.thumbnail);

             TextView serial = (TextView) convertView.findViewById(R.id.serial);
            TextView title = (TextView) convertView.findViewById(R.id.title);
            TextView rating = (TextView) convertView.findViewById(R.id.rating);
            TextView genre = (TextView) convertView.findViewById(R.id.genre);
            TextView year = (TextView) convertView.findViewById(R.id.releaseYear);

            // getting movie data for the row
            Movie m = movieItems.get(position);

            // thumbnail image
            thumbNail.setImageUrl(m.getThumbnailUrl(), imageLoader);

            // title
            title.setText(m.getTitle());

            // rating
             rating.setText("Rating: " + String.valueOf(m.getRating()));

            // genre
            String genreStr = "";
            for (String str : m.getGenre()) {
              genreStr += str + ", ";
              }
            genreStr = genreStr.length() > 0 ? genreStr.substring(0,
                 genreStr.length() - 2) : genreStr;
             genre.setText(genreStr);

            // release year
             year.setText(String.valueOf(m.getYear()));

             String color = bgColors[position % bgColors.length];
            serial.setBackgroundColor(Color.parseColor(color));




            return convertView;
     }



     public Filter getFilter() {
         return mFilter;
     }

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

        String filterString = constraint.toString().toLowerCase();

        FilterResults results = new FilterResults();

        final List<String> list = originalData;

        int count = list.size();
        final ArrayList<String> nlist = new ArrayList<String>(count);

        String filterableString ;

        for (int i = 0; i < count; i++) {
            filterableString = list.get(i);
            if (filterableString.toLowerCase().contains(filterString)) {
                nlist.add(filterableString);
            }
        }

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

        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        filteredData = (ArrayList<String>) results.values;
        notifyDataSetChanged();
    }

}



}

So can someone please tell me what I am not doing right. Thanks in advance

Upvotes: 2

Views: 1521

Answers (3)

Okechukwu Eze
Okechukwu Eze

Reputation: 149

This is how i was able to solve the misery of my searching code.

on my MainActivity

public class MainActivity extends Activity {

 private List<Movie> currentMovieList = new ArrayList<Movie>();
 private List<Movie> originalMovieList = new ArrayList<Movie>();
 private CustomListAdapter adapter;
 private ListView mList;
 // Search EditText
 EditText inputSearch;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    setContentView(R.layout.activity_main);

inputSearch = (EditText) findViewById(R.id.inputSearch);

adapter = new CustomListAdapter(this, currentMovieList);
    mList.setAdapter(adapter);


    inputSearch.addTextChangedListener(new TextWatcher() {

        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // When user changed the Text

            String filterString = cs.toString().toLowerCase();
            Log.e("TAG", "filterString:" + filterString);
            currentMovieList.clear();
            if (TextUtils.isEmpty(filterString)) {
                currentMovieList.addAll(originalMovieList);
            }

            String filterableString;
            for (Movie movie : originalMovieList) {

            //search from the title field
                if (movie.getTitle().toLowerCase().contains(filterString)) {
                    currentMovieList.add(movie);
                }
            //search from the year field
                else if (String.valueOf(movie.getYear()).toLowerCase().contains(filterString))
                {
                    currentMovieList.add(movie);
                }
            //search from the rating field
                else if (String.valueOf(movie.getRating()).toLowerCase().contains(filterString))
                {
                    currentMovieList.add(movie);
                }
            //search from the genre field
                else if (movie.getGenre().toString().toLowerCase().contains(filterString))
                {
                    currentMovieList.add(movie);
                }
            }
            adapter.notifyDataSetChanged();
            //FLAGS Cannot resolve method 'getFilter()' here
        }

        @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
        }
    });

} }

And ADD this to your CustomListAdapter

public class CustomListAdapter extends BaseAdapter implements Filterable {

    private Activity activity;
 private LayoutInflater inflater;

 private List<String>originalData = null;
 // private List<String>filteredData = null;

 private List<Movie> movieItems;
 private List<Movie> originalMovieList;
 private String[] bgColors;
 ImageLoader imageLoader = MyApplication.getInstance().getImageLoader();
 private ItemFilter mFilter = new ItemFilter();


 public CustomListAdapter(Activity activity, List<Movie> movieItems) {
       this.activity = activity;
        this.movieItems = movieItems;
      // this.originalMovieList = movieItems;
      this.originalMovieList = new ArrayList<Movie>(movieItems);
      bgColors = activity.getApplicationContext().getResources().getStringArray(R.array.movie_serial_bg);
        }

    //Add Below Method
    public void reloadData(){
       this.originalMovieList = new ArrayList<Movie>(movieItems);
     notifyDataSetChanged();
        }
     @Override
 public int getCount() {
     return movieItems.size();
        }

 @Override
    public Object getItem(int location) {
        return movieItems.get(location);
        }

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

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {

     if (inflater == null)
        inflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (convertView == null)
        convertView = inflater.inflate(R.layout.list_row_image, null);

    if (imageLoader == null)
        imageLoader = MyApplication.getInstance().getImageLoader();
    NetworkImageView thumbNail = (NetworkImageView) convertView.findViewById(R.id.thumbnail);

    TextView serial = (TextView) convertView.findViewById(R.id.serial);
    TextView title = (TextView) convertView.findViewById(R.id.title);
    TextView rating = (TextView) convertView.findViewById(R.id.rating);
    TextView genre = (TextView) convertView.findViewById(R.id.genre);
    TextView year = (TextView) convertView.findViewById(R.id.releaseYear);

    // getting movie data for the row
    Movie m = movieItems.get(position);

    // thumbnail image
    thumbNail.setImageUrl(m.getThumbnailUrl(), imageLoader);

    // title
    title.setText(m.getTitle());

    // rating
    rating.setText("Rating: " + String.valueOf(m.getRating()));

     // genre
     String genreStr = "";
        for (String str : m.getGenre()) {
          genreStr += str + ", ";
     }
     genreStr = genreStr.length() > 0 ? genreStr.substring(0,
            genreStr.length() - 2) : genreStr;
        genre.setText(genreStr);

        // release year
     year.setText(String.valueOf(m.getYear()));

     String color = bgColors[position % bgColors.length];
        serial.setBackgroundColor(Color.parseColor(color));




      return convertView;
 }


            public Filter getFilter() {
                return mFilter;
            }

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

                    String filterString = constraint.toString().toLowerCase();

                    FilterResults results = new FilterResults();


                    //results.values = nlist;
                    //results.count = nlist.size();
                    results.values = originalMovieList;
                    results.count = originalMovieList.size();

                    return results;
                }

                @SuppressWarnings("unchecked")
                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    //filteredData = (ArrayList<String>) results.values;
                    //movieItems = (ArrayList<Movie>) results.values;
                    movieItems.clear();
                    movieItems.addAll((ArrayList<Movie>) results.values);
                    notifyDataSetChanged();
                }

            }



}

Now thats a WRAP. Thanks to @DhavalPatel That Guy is an Android Guru. He made all this happen. -Happy Coding

Upvotes: 1

jily
jily

Reputation: 344

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

    String filterString = constraint.toString().toLowerCase();

    FilterResults results = new FilterResults();

    final List<Movie> list = movieItems;

    int count = list.size();
    final ArrayList<Movie> nlist = new ArrayList<Movie>(count);

    String filterableString ;

    for (int i = 0; i < count; i++) {
        filterableString = list.get(i).getName();
        if (filterableString.toLowerCase().contains(filterString)) {
            nlist.add(list.get(i));
        } 
    } 

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

    return results;
} 

@SuppressWarnings("unchecked") 
@Override 
protected void publishResults(CharSequence constraint, FilterResults results) {
    movieItems= (ArrayList<String>) results.values;
    notifyDataSetChanged();
} 

} 

Upvotes: 2

sonic
sonic

Reputation: 1904

It seems you don't use your filteredData in the adapter. So when you call notifiyDataSetChanged there is no change in the data use to fill the ListView.

The publishResults method should change the data used to populate the views, ie for you the movieItems list.

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

        String filterString = constraint.toString().toLowerCase();

        FilterResults results = new FilterResults();

        final List<Movie> list = originalMovieItems;

        int count = list.size();
        final ArrayList<Movie> nlist = new ArrayList<Movie>(count);

        String filterableString ;

        for (int i = 0; i < count; i++) {
            filterableString = list.get(i).getName();//or whatever you want to filter on
            if (filterableString.toLowerCase().contains(filterString)) {
                nlist.add(list.get(i));
            }
        }

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

        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        movieList = (ArrayList<Movie>) results.values;
        notifyDataSetChanged();
    }

}

So to keep the movie list unchanged (not the one you display but the one you filter on), you should add a originalMovieList field to your adapter class and modify the constructor as following.

public CustomListAdapter(Activity activity, List<Movie> movieItems) {
     this.activity = activity;
     this.movieItems = movieItems;
     bgColors = activity.getApplicationContext().getResources().getStringArray(R.array.movie_serial_bg);
      this.originalMovieList = movieItems;
         }

Upvotes: 1

Related Questions