Android Custom autocompletetextview freezes on backspace click - android

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

Related

How to Search in recyclerview with One Adapter in Android Studio?

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?

The content of the adapter has changed but ListView did not receive a notification. From AutoCompleteTextView

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

How to filter RecyclerView wih EditText

I am trying to search a RecylerView with EditText, i follow some tutorial and i get Error NullPointerException. my RecyclerView is working good , but my search program is not working.
this is my Adapter Code
public class ListDefoodAdapter extends RecyclerView.Adapter<ListDefoodAdapter.CategoryViewHolder> implements Filterable {
private Context context;
private ArrayList<DefoodListData> listDefood;
private ArrayList<DefoodListData> listFilter;
public ListDefoodAdapter(Context context) {
this.context = context;
}
public ArrayList<DefoodListData> getListDefood() {
return listDefood;
}
public void setListDefood(ArrayList<DefoodListData> listDefood) {
this.listDefood = listDefood;
}
#NonNull
#Override
public CategoryViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemRow = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_transaksidefood, viewGroup, false);
return new CategoryViewHolder(itemRow);
}
public Filter getFilter(){
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString();
if (charString.isEmpty()){
listDefood = listFilter;
} else {
ArrayList<DefoodListData> filteredList = new ArrayList<>();
for (DefoodListData row : listFilter){
String id = String.valueOf(row.getId());
if (id.toLowerCase().contains(charString.toLowerCase()) ||
row.getNamaUser().toLowerCase().contains(charString.toLowerCase()) ||
row.getNamaDriver().toLowerCase().contains(charString.toLowerCase())){
filteredList.add(row);
}
}
listDefood = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = listDefood;
return filterResults;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
listDefood = (ArrayList<DefoodListData>) results.values;
notifyDataSetChanged();
}
};
}
#Override
public int getItemCount() {
return getListDefood().size();
}
}
and this is my code in fragment
private void searchData(){
btn_search.setOnClickListener(v -> {
String keySearch = edt_cari.getText().toString();
listDefoodAdapter.getFilter().filter(keySearch);
});
}
but i get error null on method getItemCount(). Please help me to solve this problem
there is an issue in your data assign in listFilter.
you are adding data in listDefood in below method
public void setListDefood(ArrayList<DefoodListData> listDefood) {
this.listDefood = listDefood;
}
but you are not adding a list in listFilter.
You need to add list in Both array.
public void setListDefood(ArrayList<DefoodListData> listDefood) {
this.listDefood = listDefood;
this.listFilter = listDefood;
}
Assign filtered list size to filter result.
try with this
public void setListDefood(ArrayList<DefoodListData> listDefood) {
this.listDefood = listDefood;
this.listFilter = listDefood;
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
listDefood = (List<DefoodListData >) results.values;
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
ArrayList<DefoodListData> filteredList = new ArrayList<>();
for (DefoodListData row : listFilter) {
if (String.valueOf(row.getId().toLowerCase().trim().contains(charString)) ||
row.getNamaUser().toLowerCase().trim().contains(charString) ||
row.getNamaDriver().toLowerCase().trim().contains(charString)) {
filteredList.add(row);
}
}
results.count = filteredList.size();
results.values = filteredList;
return results;
}
};
}

custom base adapter don't work filter

i want set filter (search) in list view and use "extends BaseAdapter implements Filterable" for adapter class .
this my code :
public class UserList extends BaseAdapter implements Filterable {
private Context context;
private List<Users> user;
public UserList(Context context, List<Users> user) {
this.context = context;
this.user = user;
}
#Override
public int getCount() {
return user.size();
}
#Override
public Object getItem(int position) {
return user.get(position);
}
#Override
public long getItemId(int position) {
return user.get(position).getId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(context, R.layout.listview_item, null);
ImageView imgUser = (ImageView) view.findViewById(R.id.list_image);
TextView txtName = (TextView) view.findViewById(R.id.list_item_title);
TextView txtDesc = (TextView) view.findViewById(R.id.list_item_short);
TextView txtSex = (TextView) view.findViewById(R.id.list_item_sex);
TextView txtAge = (TextView) view.findViewById(R.id.list_item_age);
//get byte[] from db , resize and convert to bitmap
Bitmap bmp = BitmapFactory.decodeByteArray(user.get(position).getPic(), 0, user.get(position).getPic().length);
imgUser.setImageBitmap(getResizedBitmap(bmp, 300, 150));
txtName.setText(user.get(position).getUserName());
txtDesc.setText(user.get(position).getUserDesc());
txtSex.setText(user.get(position).getGender());
txtAge.setText(user.get(position).getAge() + " ساله ");
return view;
}
and this my filter method :
private Filter filterResult = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
ArrayList<Users> tempList = new ArrayList<>();
if (constraint != null && user != null) {
int length = user.size();
int i = 0;
while (i < length) {
Users item = user.get(i);
tempList.add(item);
i++;
}
filterResults.values = tempList;
filterResults.count = tempList.size();
}
return filterResults;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
user = (ArrayList<Users>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
#Override
public Filter getFilter() {
return filterResult;
}
but no happen when enter text for filter list view ... see this image :
There a few mistake in your code.
You must keep original array which did not have filter.
You should change your code like this
private List<Users> original;
private List<Users> user;
public UserList(Context context, List<Users> user) {
this.context = context;
this.user = user;
this.original = user;
}
You did not perform filter in your code. You need to correct your code
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
ArrayList<Users> tempList = new ArrayList<>();
if (original != null) {
if (TextUtil.isEmpty(constraint)){
tempList = original;
} else {
int length = user.size();
int i = 0;
while (i < length) {
User item = original.get(i);
// check item again your constraint see example below
if (item.name.contain(constraint))
tempList.add(item);
i++;
}
}
}
filterResults.values = tempList;
filterResults.count = tempList.size();
return filterResults;
}
in this case your dataset reference is changing on filter so adapter can not getting reference to your data as per my solution i will do follow
declare temp list in adapter which contain all data
private List<Users> tempuser;
now fill this with looping to avoid reference problem and call it in adapter constructor
private void fillData()
{
// initialize tempuserhere
tempuser=new List<Users>() ; //check as per your model
for(Users obj:user)
{
tempuser.add(obj);
}
}
in constructor
public UserList(Context context, List<Users> user) {
this.context = context;
this.user = user;
fillData();
}
now in filter process class
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null && tempuser != null) {
boolean fillAll=false;
user.clear();
if(constraint.toString().trim().length==0)
fillAll=true;
for(Users objUser:tempuser)
{
if(fillAll || constraint.toString().trim().toLowerCase().contains(objUser.value.toLowerCase()))///the objUser value replaced with your compare string
{
user.add(objUser);
}
}
filterResults.values = user;
filterResults.count = user.size();
}
return filterResults;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
user = (ArrayList<Users>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
you can try this if any problem let me know, also
if any user know the standarad approach let me know

android AutoCompleteTextView seems to ignore the Filter of the custom ArrayAdapter

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.

Categories

Resources