1

I have created a MultiColumn ListView with a SearchView above it. It pulls data from an SQLite database and displays in the list view. I have created a custom ArrayAdapter and the java class. However, the output from my SearchView on my 3 column custom array list view is not returning the correct data i.e. it is not filtering correctly. I have tried everything to figure what may be the issue, and been on this for the last 3 days. I am using the QueryTextChangeListerner. Any help with be appreciated, as I am at a bottleneck in my app development.

MainActivity.java:

        mSearchView = (SearchView) findViewById(R.id.search_view);
        listView = (ListView) findViewById(R.id.list_view);

        controller = new ResturantsDbHelper(this);

        userList = new ArrayList<>();

        Cursor resturantdata = controller.getResturantList();

        int numRows =resturantdata.getCount();
        if (numRows == 0) {
            Toast.makeText(SearchResturantListingX.this,"No Resturants matching your selection criteria",Toast.LENGTH_LONG).show();
        }
        else {
            while (resturantdata.moveToNext()) {
                user = new User(resturantdata.getString(1),resturantdata.getString(2),resturantdata.getString(3),resturantdata.getString(4),resturantdata.getString(5));

                userList.add(user);
            }
            //FINISH Populating the array variable with the string data from SQLIte database

            adapter = new FiveColumn_ListAdapter(this,R.layout.activity_search_main3_resturant_list,userList);

            listView.setAdapter(adapter);
        }

        listView.setTextFilterEnabled(true);
        setupSearchView();
    }

    private void setupSearchView() {
        mSearchView.setIconifiedByDefault(false);
        mSearchView.setOnQueryTextListener(this);
        mSearchView.setSubmitButtonEnabled(true);
        mSearchView.setQueryHint("Search Here By Name");
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        adapter.getFilter().filter(newText);
        return false;
    }
}

Here is my Java class which defines my ListItems:

public class User {
    private String resturantName;
    private String resturantType;
    private String resturantLocation;

    public User (String resturantName, String resturantType, String resturantLocation, String rOpening, String rClosing){
        super();
        this.resturantName = resturantName;
        this.resturantType = resturantType;
        this.resturantLocation = resturantLocation;
    }

    public String getResturantName() {
        return resturantName;
    }

    public void setResturantName (String resturantName) {
        this.resturantName = resturantName;
    }

    public String getResturantType() {
        return resturantType;
    }

    public void setType (String resturantType) {
        this.resturantType = resturantType;
    }

    public String getResturantLocation() {
        return resturantLocation;
    }

    public void setLocation (String resturantLocation) {
        this.resturantLocation = resturantLocation;
    }

    public User(String resturantName, String type, String location) {
        super();
        this.resturantName = resturantName;
    }

    @Override
    public String toString() {
        return  resturantName + " ";  
    }
}

Here is my custom Adapter:

public class FiveColumn_ListAdapter extends ArrayAdapter<User> {

    private LayoutInflater mInflater;
    private ArrayList<User> users;
    private int mViewResourceId;

    public FiveColumn_ListAdapter(Context context, int textViewResourceId, ArrayList<User> users) {
        super(context,textViewResourceId,users);
        this.users = users;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mViewResourceId = textViewResourceId;
    }

    public View getView(int position, View convertView, ViewGroup parents) {
        convertView = mInflater.inflate(mViewResourceId,null);

        User user =users.get(position);

        if (user != null) {
            TextView name=(TextView)convertView.findViewById(R.id.resturantName);
            TextView type=(TextView)convertView.findViewById(R.id.resturantType);
            TextView location=(TextView)convertView.findViewById(R.id.resturantLocation);

            if(name !=null) {
                name.setText((user.getResturantName()));
            }

            if(type !=null) {
                type.setText((user.getResturantType()));
            }

            if(location !=null) {
                location.setText((user.getResturantLocation()));
            }

        }
        return convertView;
    }
}
TofferJ
  • 4,678
  • 1
  • 37
  • 49
Noruwa
  • 93
  • 9

2 Answers2

0
  1. First you need to change items collection, to be sorteed all time. One of this example.

    private Set<User> users; ..... users = new SortedSet<>();

  2. Change you implementation of User Objects, to contains Comparable interface. For ex. below.

      class Movie implements Comparable<Movie> 
     { 
    private double rating; 
    private String name; 
    private int year; 
    
    // Used to sort movies by year 
    public int compareTo(Movie m) 
    { 
        return this.year - m.year; 
    } 
    
    // Constructor 
    public Movie(String nm, double rt, int yr) 
    { 
        this.name = nm; 
        this.rating = rt; 
        this.year = yr; 
    } 
    
    // Getter methods for accessing private data 
    public double getRating() { return rating; } 
    public String getName()   {  return name; } 
    public int getYear()      {  return year;  } 
    

    }

Then you can configure all your sorting, as you expect in above methods compareTo. See more information about Comparable Interface.

GensaGames
  • 5,538
  • 4
  • 24
  • 53
0

FiveColumn_ListAdapter must implement android.widget.Filterable

then add these codes to FiveColumn_ListAdapter:

public class FiveColumn_ListAdapter extends ArrayAdapter<User> 
                                implements android.widget.Filterable {

private LayoutInflater mInflater;
private ArrayList<User> users;// this is filtered users a subset of AllUsers
private int mViewResourceId;
private ArrayList<User> AllUsers;// AllUsers is users without any filter

public FiveColumn_ListAdapter(Context context, int textViewResourceId, 
                                             ArrayList<User> users, String initialQuery) {
    super(context,textViewResourceId,users);
    this.AllUsers = users;
    mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mViewResourceId = textViewResourceId;
    getFilter().filter(initialQuery);// perform fiter to populate users filter may be empty String
}

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence query) {

                FilterResults filterResults = new FilterResults();
                if(AllUsers == null || AllUsers.size() == 0){
                     filterResults.count = 0;
                     filterResults.values = null;
                     return filterResults;
                }
                ArrayList<User> results = new ArrayList<>();
                for (User user : AllUsers) {
                      if(query.toString().equals(user.getResturantName())// do any filtering here
                         results.add(user);
                }
                filterResults.count = results.size();
                filterResults.values = results;
                return filterResults;
            }
            ///////////////////////////////
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                users = results.values// 
            }
        };
    }
ygngy
  • 3,630
  • 2
  • 18
  • 29
  • thanks GensaGames, BAHMAN, I will give both solutions a try and let you know how it goes – Noruwa Sep 10 '18 at 21:45
  • Ok, let me tell you what I have done, I included the widget Filterable and included the codes that it supports, then i replaced all my codes in the getView method with the code in the public Filter getFilter() method and imported all the filters objects. however the code if(query.toString().equals(AllUsers.getResturantName()) gives me an error saying "cannot resolve method getResturantname() and the last line of code users = results.values// gives me an error saying incompatible type. Am i missing something? – Noruwa Sep 10 '18 at 23:09
  • @Noruwa I DO NOT DELETE `getView` simply because I DO NOT CHANGE THAT METHOD i do not add it to my answer so DO NOT replace `getView` method with the code in the `getFilter()` these are two separate methods with different jobs – ygngy Sep 11 '18 at 08:53
  • @Noruwa `if(query.toString().equals(AllUsers.getResturantName())` this code is a sample code you need to change it with what you want the user search for example this code tries to accept items which their resturant name equals the query which is entered in search box. but your second question about incompatible type if you see my code i have set `filterResults.values = results;` in method `performFiltering` then i return `filterResults` from that method. what you receive in method `publishResults` in argument `FilterResults results` is what you return in method `performFiltering`. – ygngy Sep 11 '18 at 08:53
  • @Noruwa if this was accepted answer to your question then accept the answer, plz – ygngy Sep 12 '18 at 10:17