2

I am trying to implement search functionality in a listview built into a fragment. The listview is working fine, but when I type on the edittext to search, it disappears.

My code:

public class DrinksFragment extends Fragment {

    private View rootView;
    private ArrayAdapter<DrinksList> adapter;
    private List<DrinksList> drinks;
    private ListView lv;
    ArrayList<DrinksList> mAllData;
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.activity_drinks_fragment, container, false);
        populateDrinksList();
        doSearch();
        return rootView;
    }

    private void doSearch() {
        final EditText et = (EditText)rootView.findViewById(R.id.searchListDrinks);
        et.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) {
                
            }

            @Override
            public void afterTextChanged(Editable s) {
                String text = et.getText().toString().toLowerCase(Locale.getDefault());
            adapter.filter(text);
            }
        });
    }



    private void populateDrinksList() {
        drinks = new ArrayList<DrinksList>();
        drinks.add(new DrinksList(R.drawable.coca, "Coca Cola", 2.50));
        drinks.add(new DrinksList(R.drawable.cocalight, "Coca Cola Light", 2.50));
        drinks.add(new DrinksList(R.drawable.cocazero, "Coca Cola Zero", 2.50));
        drinks.add(new DrinksList(R.drawable.orange, "Fanta Orange", 2.50));
        drinks.add(new DrinksList(R.drawable.lemon, "Fanta Lemon", 2.50));
        drinks.add(new DrinksList(R.drawable.ble, "Fanta Blue", 2.50));
        drinks.add(new DrinksList(R.drawable.sprite, "Sprite", 2.50));
        drinks.add(new DrinksList(R.drawable.soda, "Soda Water", 2.50));
        drinks.add(new DrinksList(R.drawable.tonic, "Tonic Water", 2.50));
        drinks.add(new DrinksList(R.drawable.ioli, "Sparkling Water Ioli", 2.50));
        drinks.add(new DrinksList(R.drawable.perrier, "Sparkling Water Perrier", 2.50));
        drinks.add(new DrinksList(R.drawable.nero, "Still Water", 2.00));
        drinks.add(new DrinksList(R.drawable.redbull, "Red Bull", 4.00));
        drinks.add(new DrinksList(R.drawable.zelita, "Zelita", 2.50));
        lv = (ListView)rootView.findViewById(R.id.drinksListView);
        adapter = new MyCustomDrinksListAdapter(getActivity().getApplicationContext(), R.layout.list_item, drinks);
        lv.setAdapter(adapter);
    }

}public class DrinksFragment extends Fragment {

    private View rootView;
    private ArrayAdapter<DrinksList> adapter;
    private List<DrinksList> drinks;
    private ListView lv;
    ArrayList<DrinksList> mAllData;
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.activity_drinks_fragment, container, false);
        populateDrinksList();
        doSearch();
        return rootView;
    }

    private void doSearch() {
        final EditText et = (EditText)rootView.findViewById(R.id.searchListDrinks);
        et.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) {
                DrinksFragment.this.adapter.getFilter().filter(s);
            }

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



    private void populateDrinksList() {
        drinks = new ArrayList<DrinksList>();
        drinks.add(new DrinksList(R.drawable.coca, "Coca Cola", 2.50));
        drinks.add(new DrinksList(R.drawable.cocalight, "Coca Cola Light", 2.50));
        drinks.add(new DrinksList(R.drawable.cocazero, "Coca Cola Zero", 2.50));
        drinks.add(new DrinksList(R.drawable.orange, "Fanta Orange", 2.50));
        drinks.add(new DrinksList(R.drawable.lemon, "Fanta Lemon", 2.50));
        drinks.add(new DrinksList(R.drawable.ble, "Fanta Blue", 2.50));
        drinks.add(new DrinksList(R.drawable.sprite, "Sprite", 2.50));
        drinks.add(new DrinksList(R.drawable.soda, "Soda Water", 2.50));
        drinks.add(new DrinksList(R.drawable.tonic, "Tonic Water", 2.50));
        drinks.add(new DrinksList(R.drawable.ioli, "Sparkling Water Ioli", 2.50));
        drinks.add(new DrinksList(R.drawable.perrier, "Sparkling Water Perrier", 2.50));
        drinks.add(new DrinksList(R.drawable.nero, "Still Water", 2.00));
        drinks.add(new DrinksList(R.drawable.redbull, "Red Bull", 4.00));
        drinks.add(new DrinksList(R.drawable.zelita, "Zelita", 2.50));
        lv = (ListView)rootView.findViewById(R.id.drinksListView);
        adapter = new MyCustomDrinksListAdapter(getActivity().getApplicationContext(), R.layout.list_item, drinks);
        lv.setAdapter(adapter);
    }

}

My Adapter:

public class MyCustomDrinksListAdapter extends ArrayAdapter<DrinksList> {


    private List<DrinksList> items = null;
    private ArrayList<DrinksList> arraylist;
    public MyCustomDrinksListAdapter(Context context, int layoutId, List<DrinksList> items) {
        super(context, layoutId, items);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View arrayView = convertView;
        if(arrayView == null){
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            arrayView = vi.inflate(R.layout.list_item, parent, false);
        }

        DrinksList currentPosition = getItem(position);
        if(currentPosition != null){
            ImageView image = (ImageView)arrayView.findViewById(R.id.product_image_coffee);
            image.setImageResource(currentPosition.getImage());

            TextView name = (TextView)arrayView.findViewById(R.id.product_name_coffee);
            name.setText(currentPosition.getName());

            TextView price = (TextView)arrayView.findViewById(R.id.product_price_coffee);
            price.setText(String.format("%.2f", currentPosition.getPrice()));
        }
        return arrayView;
    }

    public void filter(String charText) {
        charText = charText.toLowerCase(Locale.getDefault());
        items.clear();
        if (charText.length() == 0) {
            items.addAll(arraylist);
        } else {
            for (DrinksList wp : arraylist) {
                if (wp.getName().toLowerCase(Locale.getDefault())
                        .contains(charText)) {
                    items.add(wp);
                }
            }
        }
        notifyDataSetChanged();
    }
}

I tried following the android developers example but I could not.

peterh
  • 11,875
  • 18
  • 85
  • 108
Kostas Drak
  • 3,222
  • 6
  • 28
  • 60

4 Answers4

7

Instead of adding filter method in Adapter class. .. add it in you fragment.. like this..

    public class DrinksFragment extends Fragment {

    private View rootView;
    private ArrayAdapter<DrinksList> adapter;
    private List<DrinksList> drinks;
    private ListView lv;
    ArrayList<DrinksList> mAllData=new ArrayList<DrinksList>();
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.activity_drinks_fragment, container, false);
        populateDrinksList();
        doSearch();
        return rootView;
    }

    private void doSearch() {
        final EditText et = (EditText)rootView.findViewById(R.id.searchListDrinks);
        et.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) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                String text = et.getText().toString().toLowerCase(Locale.getDefault());
            filter(text);
            }
        });
    }



    private void populateDrinksList() {
        drinks = new ArrayList<DrinksList>();
        drinks.add(new DrinksList(R.drawable.coca, "Coca Cola", 2.50));
        drinks.add(new DrinksList(R.drawable.cocalight, "Coca Cola Light", 2.50));
        drinks.add(new DrinksList(R.drawable.cocazero, "Coca Cola Zero", 2.50));
        drinks.add(new DrinksList(R.drawable.orange, "Fanta Orange", 2.50));
        drinks.add(new DrinksList(R.drawable.lemon, "Fanta Lemon", 2.50));
        drinks.add(new DrinksList(R.drawable.ble, "Fanta Blue", 2.50));
        drinks.add(new DrinksList(R.drawable.sprite, "Sprite", 2.50));
        drinks.add(new DrinksList(R.drawable.soda, "Soda Water", 2.50));
        drinks.add(new DrinksList(R.drawable.tonic, "Tonic Water", 2.50));
        drinks.add(new DrinksList(R.drawable.ioli, "Sparkling Water Ioli", 2.50));
        drinks.add(new DrinksList(R.drawable.perrier, "Sparkling Water Perrier", 2.50));
        drinks.add(new DrinksList(R.drawable.nero, "Still Water", 2.00));
        drinks.add(new DrinksList(R.drawable.redbull, "Red Bull", 4.00));
        drinks.add(new DrinksList(R.drawable.zelita, "Zelita", 2.50));

mAllData.addAll(drinks);
        lv = (ListView)rootView.findViewById(R.id.drinksListView);
        adapter = new MyCustomDrinksListAdapter(getActivity().getApplicationContext(),        R.layout.list_item, drinks);
        lv.setAdapter(adapter);
    }


public void filter(String charText) {
        charText = charText.toLowerCase(Locale.getDefault());
        drinks .clear();
        if (charText.length() == 0) {
            drinks.addAll(mAllData);
        } else {
            for (DrinksList wp : mAllData) {
                if (wp.getName().toLowerCase(Locale.getDefault())
                        .contains(charText)) {
                    drinks .add(wp);
                }
            }
        }
        notifyDataSetChanged();
    }

}

and you Adapter class will remain as it is(remove filter method)..

 public class MyCustomDrinksListAdapter extends ArrayAdapter<DrinksList> {


   // private List<DrinksList> items = null; // no use
    private ArrayList<DrinksList> arraylist;
    public MyCustomDrinksListAdapter(Context context, int layoutId, List<DrinksList> items) {
        super(context, layoutId, items);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View arrayView = convertView;
        if(arrayView == null){
            LayoutInflater vi;
            vi = LayoutInflater.from(getContext());
            arrayView = vi.inflate(R.layout.list_item, parent, false);
        }

        DrinksList currentPosition = getItem(position);
        if(currentPosition != null){
            ImageView image = (ImageView)arrayView.findViewById(R.id.product_image_coffee);
            image.setImageResource(currentPosition.getImage());

            TextView name = (TextView)arrayView.findViewById(R.id.product_name_coffee);
            name.setText(currentPosition.getName());

            TextView price = (TextView)arrayView.findViewById(R.id.product_price_coffee);
            price.setText(String.format("%.2f", currentPosition.getPrice()));
        }
        return arrayView;
    }


}

Thank you. Hope it works...!!1

iMDroid
  • 2,108
  • 1
  • 16
  • 29
3

Your custom adapter must implement Filterable interface, and you should override getFilter () method.

refer to this answer: How to implement getfilter() with custom adapter that extends baseadapter

Community
  • 1
  • 1
Silvia H
  • 8,097
  • 7
  • 30
  • 33
  • and in the getFilter method what am i supposed to do? – Kostas Drak Nov 13 '14 at 22:04
  • GetFilter method should define how you want the search to be implemented, since you're using an arraylist of custom objects (DrinksList) not primitive data types. – Silvia H Nov 13 '14 at 22:12
  • Check the link I posted. – Silvia H Nov 13 '14 at 22:12
  • i am trying to follow this example http://www.androidbegin.com/tutorial/android-search-filter-listview-images-and-texts-tutorial/ but for some reason my adapter from fragment cant see the filter method from custom adapter class – Kostas Drak Nov 13 '14 at 22:27
  • i posted...take a look please – Kostas Drak Nov 13 '14 at 22:56
  • I don't see a problem with your filter() method, could you update the code in doSearch ()? How do you call filter () in your fragment? – Silvia H Nov 13 '14 at 22:58
  • For some reason it gives me an error of null pointer exception – Kostas Drak Nov 13 '14 at 23:10
  • Don't create another instance from your adapter and set it to the listView, use the already defined object, like this: adapter.filter (s.toString ()); . And I think extending BaseAdapter class will work better than ArrayAdapter – Silvia H Nov 13 '14 at 23:13
  • it says cannot resolve method filter when i used it the way you propose – Kostas Drak Nov 13 '14 at 23:15
  • Because adapter object is defined globally as ArrayAdapter adapter, it should be like this: MyCustomDrinksListAdapter adapter – Silvia H Nov 13 '14 at 23:17
  • again the same error. Null Pointer exception..the same when i extended the baseadapter – Kostas Drak Nov 13 '14 at 23:24
  • Exception in which line exactly? – Silvia H Nov 13 '14 at 23:25
  • According to the example i followed i have updated how i use the filter..take a look please at my code and at this example http://www.androidbegin.com/tutorial/android-search-filter-listview-images-and-texts-tutorial/ – Kostas Drak Nov 13 '14 at 23:34
  • i guess the null pointer exception is because i call the filter inside the afterTextChanged so the text is null. – Kostas Drak Nov 13 '14 at 23:42
2

I figured out that problem is with the Constructor of MyCustomDrinksListAdapter class. Initialize arraylist in constructor like this:

arraylist = new ArrayList<DrinksList>();
this.arraylist.addAll(items);

You don't need to extend from base adapter just change you constructor. Another thing it looks you are not familiar with concept of ViewHolder. Search and use it in your getView() it'll improve performance. yet your remaining code is correct but constructor. if you need any other help you can ask.

Michele La Ferla
  • 6,775
  • 11
  • 53
  • 79
Muhammad Ali
  • 522
  • 2
  • 6
  • 18
  • the constructor works fine as it is and the listview running fine...however why should i use the vieholder class?? what will improve?? and also the question is about implementing search in the listview with custom adapter – Kostas Drak Nov 20 '14 at 22:02
  • The reason you need to change constructor is that there are two lists one is items and the other is arraylist, which is permanent.You need to initialize arrayList otherwise how can you keep track of all the drinkItems?Look your list items is used as temporary bases and when you search for example "c" all items containing "c" will be inserted into items from array list.If you don't initialize arraylist in constructor how can it be a permanent storage for all items.Do it and see your self. – Muhammad Ali Nov 21 '14 at 04:42
  • And regarding ViewHolder it will improve performance. see findViewById() methods uses CPU why you need to find an item one you have already referred it? View Holder's purpose is to check if you already have reference of some control like TextView then don't find it again.here is an example http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html – Muhammad Ali Nov 21 '14 at 04:48
  • You have already implemented code for search in filter method and you have also called it at right place.What you need now is just initialize arraylist like this. arraylist = new ArrayList(); this.arraylist.addAll(items); – Muhammad Ali Nov 21 '14 at 07:07
1

This is the code you need to use to implement a srach on the listview:

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

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

Taken from the following tutorial. Hope it helps :)

Michele La Ferla
  • 6,775
  • 11
  • 53
  • 79