I want to search in recyclerview.
I write the Filter method in recyclerview adapter like this:
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults oReturn = new FilterResults();
final ArrayList<Info_Filter> results = new ArrayList<Info_Filter>();
if (orig == null)
orig = items;
if (constraint != null) {
if (orig != null & orig.size() > 0) {
for (final Info_Filter g : orig) {
if (g.getName().toLowerCase().contains(constraint.toString()))
results.add(g);
}
}
oReturn.values = results;
}
return oReturn;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<Info_Filter>) results.values;
notifyDataSetChanged();
}
};
}
Its ok, now I have another recycler that work with this adapter and this data model. Each one have a edit text to search. when I write something in first edit text, recyclerview number 2 changes.
How I can search for both recyclers?
First, create a class which extends Filter
public class NewFilter extends Filter {
private recyclerAdapter adapter;
private ArrayList<Info_Filter> filterList;
NewFilter(ArrayList<Info_Filter> filterList, recyclerAdapter adapter) {
this.adapter = adapter;
this.filterList = filterList;
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
constraint = constraint.toString().toUpperCase();
ArrayList<Info_Filter> filteredInfo = new ArrayList<>();
for (int i = 0; i < filterList.size(); i++) {
if (filterList.get(i).getName().toLowerCase().contains(constraint)) {
filteredInfo.add(filterList.get(i));
}
}
results.count = filteredInfo.size();
results.values = filteredInfo;
} else {
results.count = filterList.size();
results.values = filterList;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
adapter.mDataSet = (ArrayList<Info_Filter>) results.values;
adapter.notifyDataSetChanged();
}
}
Now implement the Filterable interface to your RecyclerView Adapter and override the getFilter() method.
#Override
public Filter getFilter() {
if (filter == null) {
filter = new NewFilter(filterMDataSet, this);
}
return filter;
}
filterMDataSet can be a copy of the ArrayList that you pass to the adapter when setting the adapter to you recyclerview. You could create another ArrayList in the adapter and initialize it in the constructor with the same data as the main ArrayList.
Now its tike to filter the results using a text. You can run this code with the text that you need to filter.
if (recyclerView.getAdapter() != null) {
((YourAdapter) yourAdapter).getFilter().filter(text_to_filter);
}
Check if this works?
Related
I got this problem from my AutoCompleteTextView when I select.
How can I solve this error ?
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. Make sure your adapter calls notifyDataSetChanged() when its content changes.
Code:
public class AutoSuggestAdapter extends ArrayAdapter<String> implements Filterable {
List<String> shippers;
public AutoSuggestAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
shippers = new ArrayList<String>();
}
public void setData(List<String> stringList) {
}
#Override
public int getCount() {
return shippers.size();
}
#Override
public String getItem(int index) {
return shippers.get(index);
}
#Override
public Filter getFilter() {
Filter myFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
Logger.d("Start load address");
new QueryAddressRepository(getContext()).getAdressList(constraint.toString(), address_list -> {
shippers = address_list;
Logger.d("Done");
});
// Now assign the values and count to the FilterResults object
filterResults.values = shippers;
filterResults.count = shippers.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence contraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
return myFilter;
}
}
I am using a autocompletetextview with custom adapter in android. it works fine. But when i click backspace to clear selected item from autocomplete textview it freezes, or there is a delay in deleting. How can i overcome this ? My filter codes are given below
#Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
suggestions.clear();
FilterResults filterResults = new FilterResults();
for (Names people : tempItems) {
if(people.getName().toLowerCase().contains(constraint.toString()
.toLowerCase())) {
suggestions.add(people);
}
}
// FilterResults filterResults = new FilterResults();
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
} else {
return new FilterResults();
}
}
#Override
protected void publishResults(CharSequence constraint, FilterResults
results) {
List<Names> filterList = (ArrayList<Names>) results.values;
if (results != null && results.count > 0) {
clear();
for (Names people : filterList) {
add(people);
notifyDataSetChanged();
}
}
}
};
What am i doing wrong ? Thanks in Advance.
Modify you filter according to the below code. You are notifying the adapter inside the loop, it should be notified once the whole list is added into the other list i.e. outside the loop.
// This is my whole adapter and works like a charm and about the updation on the UI thread, yes I am notifying the adapter on the UI thread.
public class SuburbSuggestionsAdapter extends ArrayAdapter<String> implements Filterable {
protected static final String TAG = "SuggestionAdapter";
private List<String> suggestions;
private Context context;
private List<String> SuburbList = new ArrayList<>();
public SuburbSuggestionsAdapter(Context context) {
super(context, android.R.layout.simple_dropdown_item_1line);
suggestions = new ArrayList<String>();
this.context = context;
}
#Override
public int getCount() {
return (null != suggestions ? suggestions.size() : 0);
}
#Override
public String getItem(int index) {
return suggestions.get(index);
}
#Override
public Filter getFilter() {
Filter myFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(!TextUtils.isEmpty(constraint)){
WebServiceHandler.hitFetchSuburbList(context, constraint.toString(), new CallbackRest() {
#Override
public void onDone(String response) {
if(SuburbList.size()!=0){
SuburbList.clear();
}
try {
JSONArray jsonArray = new JSONArray(response);
for(int i=0; i<jsonArray.length(); i++){
SuburbList.add(jsonArray.get(i).toString());
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
// A class that queries a web API, parses the data and
// returns an ArrayList<GoEuroGetSet>
List<String> new_suggestions = SuburbList;
suggestions.clear();
for (int i=0;i<new_suggestions.size();i++) {
suggestions.add(new_suggestions.get(i));
}
// Now assign the values and count to the FilterResults
filterResults.values = suggestions;
filterResults.count = suggestions.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence contraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
return myFilter;
}
}
I am facing a problem of my filtered ListView not updating.
In my application there is a custom ListView which has a two TextView and one ImageView as a row elements.
The filter works fine but my custom ListView is not updated in publishResults().
#Override
protected FilterResults performFiltering(CharSequence constraint)
{
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() <= 0) {
results.count = ListAdapter.this.mStringFilterList.size();
results.values = ListAdapter.this.mStringFilterList;
} else {
ArrayList<Ezomart> filterList = new ArrayList();
for (int i = 0; i < ListAdapter.this.mStringFilterList.size(); i++) {
if (((Ezomart) ListAdapter.this.mStringFilterList.get(i)).getTitle().toUpperCase().contains(constraint.toString().toUpperCase())) {
Ezomart country = new Ezomart();
country.setTitle(((Ezomart)ListAdapter.this.mStringFilterList.get(i)).getTitle());
Log.d("SRI",mStringFilterList.get(i).getTitle());
country.setSubCategory(((Ezomart) ListAdapter.this.mStringFilterList.get(i)).getSubCategory());
country.setArea(((Ezomart) ListAdapter.this.mStringFilterList.get(i)).getArea());
country.setThumbnailUrl(((Ezomart) ListAdapter.this.mStringFilterList.get(i)).getThumbnailUrl());
country.setNumber(((Ezomart) ListAdapter.this.mStringFilterList.get(i)).getNumber());
filterList.add(country);
}
}
results.count = filterList.size();
results.values = filterList;
}
return results;
}
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
ListAdapter.this.ezoItems = (List<Ezomart>) filterResults.values;
if (filterResults.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
I found the answer by following the link below. Thanks to MBH.
I had to add this code in my fragment.
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// What i have added is this
setHasOptionsMenu(true);
}
For reference please follow the link:
Android search with Fragments
I have an Activity which has a Action Bar on the top with a Search View.
Also i am using Custom List View and want to filter from the key words entered in the search view should be associated with a particular text view in the List View Item.
in your onQueryTextChange(String Text) method of Listener use:
adapter.getFilter().filter(Text.toString()); and implement your filter in your BaseAdapter class.
here is the sample code:
#Override
public Filter getFilter()
{
return filter;
}
private GameFilter filter;
private class GameFilter extends Filter
{
public GameFilter() { }
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults oReturn = new FilterResults();
ArrayList<ItemDetails> results = new ArrayList<ItemDetails>();
if (orig == null)
orig = itemDetailsrrayList;
if (constraint != null)
{
if (orig != null && orig.size() > 0) {
for (ItemDetails g : orig) {
if (g.getName().toLowerCase().contains(constraint.toString().toLowerCase()))
results.add(g);
}
}
oReturn.values = results;
}
return oReturn;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results)
{
itemDetailsrrayList = (ArrayList<ItemDetails>)results.values;
notifyDataSetChanged();
}
}
All I want to do is displaying a CheckBox at each result of the AutoCompleteTextView's results (which are strings).
I wrote an custom Array Adapter which implements Filterable. I added a simple Filter wich gets called (I checked that) and returns the expected results. However the displayed results are completely different ones.
Here is my Filter-Code:
private class MyFilter extends Filter
{
#Override
protected FilterResults performFiltering(CharSequence constraint)
{
FilterResults results = new FilterResults();
if ((constraint == null) || (constraint.length() == 0))
{
synchronized (mLock)
{
ArrayList<String> list = new ArrayList<String>();
results.values = list;
results.count = list.size();
}
}
else
{
String constr = constraint.toString().toLowerCase();
final ArrayList<String> newItems = new ArrayList<String>();
for (String temp : items)
{
if (temp.toLowerCase().startsWith((constr)))
{
newItems.add(temp);
}
}
results.values = newItems;
results.count = newItems.size();
}
return results;
}
#Override
protected void publishResults(CharSequence constraint,
FilterResults results)
{
if (results.count > 0)
{
notifyDataSetChanged();
}
else
{
notifyDataSetInvalidated();
}
}
}
Do I miss something?
Thank you!
I forgot to set my results as the new items of the adapter.