0

Is this a right way to filter an ArrayList containing text from strings.xml? I get nothing in the ListView when I enter some characters inside SearchView.

public class SearchActivity extends AppCompatActivity  {
    private ListView searchList;
    private SearchListAdapter searchListAdapter;
    private ArrayList<listContents> listArray;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);

        searchList = (ListView)findViewById(R.id.searchList);


        listContents listC[] = new listContents[]{

                new listContents(R.string.UtrujjTitle,R.string.UtrujjContent,R.drawable.image1),
                new listContents(R.string.AruzzTitle,R.string.AruzzContainer,R.drawable.image2),
                new listContents(R.string.ArzTitle,R.string.ArzContainer,R.drawable.image3)
        };

        listArray = new ArrayList<>(Arrays.asList(listC));
        searchListAdapter = new SearchListAdapter(getApplicationContext(),listArray);
        searchList.setAdapter(searchListAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.search, menu);

        final SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

        SearchView searchView = (SearchView) menu.findItem(R.id.searchable).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) { 
                ArrayList<listContents> filtered = new ArrayList<listContents>();

                for (int i = 0; i < listArray.size() ; i++){
                    String title = String.valueOf(listArray.get(i).getTitleList());
                    String contain = String.valueOf(listArray.get(i).getContentList());

                    if (title.contains(newText) || contain.contains(newText)){

                        listContents contents = new listContents(listArray.get(i).getTitleList(),
                                listArray.get(i).getContentList(),listArray.get(i).getImageList());

                        filtered.add(contents);
                    }

                    searchListAdapter = new SearchListAdapter(getApplicationContext(),filtered);
                    searchList.setAdapter(searchListAdapter);
                }

                return false;
            }
        });
        return true;
    }
}

Adapter class

    public class SearchListAdapter extends ArrayAdapter<listContents> {

    private Context context;
    private listContents[] listContentsList;
    private ArrayList<listContents> lister;

    public SearchListAdapter(Context context, ArrayList<listContents> list ) {
        super(context,0,list);
        this.context = context;
        this.lister = list;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        listContents listContents = getItem(position);

        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.listresults, parent, false);
        }

        TextView title = (TextView) convertView.findViewById(R.id.listTitle);
        title.setText(listContents.getTitleList());

        TextView content = (TextView)convertView.findViewById(R.id.listContain);
        content.setText(listContents.getContentList());

        ImageView imageView = (ImageView)convertView.findViewById(R.id.listImage);
        imageView.setImageResource(listContents.getImageList());

        return convertView;
    }
}
3
  • You should create the new SearchListAdapter and call searchList.setAdapter(searchListAdapter); outside the for loop so it is only done once after all filtered items have been added. Besides that have you tried calling searchList.notifyDataSetChanged(); after setting the adapter? If yes and still no results are shown are you sure anything is ever being added to filtered? Might want to add a Log statement or debug that method to be sure. Commented Apr 18, 2016 at 15:33
  • I used Log.i("Elements Size", "Size is" + filtered.size()); and I get Size is0 Commented Apr 18, 2016 at 17:00
  • So something must be wrong with the custom filter. Looking at it again I do see a couple other issues but I would switch to using the default filtering capabilities of the ArrayAdapter as shown in the answer from @AllenG. Commented Apr 18, 2016 at 17:08

2 Answers 2

2

ArrayAdapter has filtering logic built in to the class, so you don't really need to create a new adapter each time a query is made, you can just run the filter method using the query string. Try this:

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            searchListAdapter.getFilter().filter(newText);

            return true;
        }
    });

The ArrayAdapter filter internally uses the toString value of your class when performing the comparison, so you will need to override toString for listContents, e.g. to something like this:

@Override
public String toString() {
    return getTitleList() + " - " + getContentList();
}


Edit: I noticed that you're passing in the resource ids instead of the actual string to the listContents class. Values such as R.string.UtrujjTitle are just integers which are identifiers for an actual string.

Assuming that getTitleList() isn't returning the actual string, but merely returns the resource id, then the above toString method will not work. Whichever filtering approach you take, you'll need to obtain the actual string from the resource id to do the comparison.

You're options, then, are either to change your code to store the actual String inside listContents instead of the resource id, or pass in a Context reference.

With a Context reference, you can make the following change to toString():

@Override
public String toString() {
    return context.getString(getTitleList()) + " - " + context.getString(getContentList());
}


Edit 2: Looking over your filtering code, the bug most likely is due to the following 2 lines:

String title = String.valueOf(listArray.get(i).getTitleList());
String contain = String.valueOf(listArray.get(i).getContentList());

Instead, you probably meant to do (assuming the getters are returning a resource id) is:

String title = getString(listArray.get(i).getTitleList());
String contain = getString(listArray.get(i).getContentList());

However, there's most likely going to be more overhead reinstantiating an adapter over reusing the same one while using its filter functionality. But if you want to keep what you already have, this change may fix it.

Sign up to request clarification or add additional context in comments.

3 Comments

Default ArrayFilter calls notifyDataSetChanged() itself once filtering is complete so calling it after filter() is not necessary.
The problem is the parameters for Arraylist are integer not string
Updated my answer to help with your issue.
0

Here,

ArrayList channelData = new ArrayList<>(); ArrayList filtered_channelData = new ArrayList<>();

edt_search_channel.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { }

        @Override
        public void onTextChanged(CharSequence charSequence, int start, int before, int count) {

            if (filtered_channelData != null) {
                filtered_channelData.clear();
                Log.d("mytag", "list is clear" + filtered_channelData.size());
            }

            for (int i = 0; i < channelData.size(); i++) {
                if (channelData.get(i).getName().toLowerCase().trim()
                        .contains(edt_search_channel.getText().toString().toLowerCase().trim())) {
                    filtered_channelData.add(channelData.get(i));

                    HashSet hs = new HashSet();
                    hs.addAll(filtered_channelData);
                    filtered_channelData.clear();
                    filtered_channelData.addAll(hs);
                }
            }
            channelAdapter = new ChannelAdapter(context, filtered_channelData, dialogChannel);
            rv_channel.setAdapter(channelAdapter);
            Log.d("mytag", "filtered_skill_listing size in out of for loop" + filtered_channelData.size());
            channelAdapter.notifyDataSetChanged();
        }

        @Override
        public void afterTextChanged(Editable editable) {
            if (edt_search_channel.getText().toString().equals("")) {
                channelAdapter = new ChannelAdapter(context, channelData, dialogChannel);
                rv_channel.setAdapter(channelAdapter);
                channelAdapter.notifyDataSetChanged();
            }
        }
    });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.