I've done a fair bit of Google-fu but I cannot figure out what's wrong. Filtering works, the drop down list appears. But the AutoCompleteTextView doesn't populate with the selected item! Can anyone help?
I set a custom adapter to my AutoCompleteTextView that shows a custom layout.
actv = (AutoCompleteTextView) root.findViewById(R.id.actv);
actv.setAdapter(new MyCustomAutoCompleteAdapter(getActivity()));
Here are the important parts MyCustomAutoCompleteAdapter code:
public class MyCustomAutoCompleteAdapter extends ArrayAdapter<String>
implements Filterable {
Context mContext;
private ArrayList<String> resultList = new ArrayList<>();
public MyCustomAutoCompleteAdapter(Context context) {
// is this the correct way to super?
super(context, R.layout.my_custom_layout);
mContext = context;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
...
return convertView;
}
#Override
public int getCount() {
return resultList.size();
}
#Override
public String getItem(int index) {
return resultList.get(index);
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
// Retrieve the autocomplete results.
resultList = doPlacesSearchQuery(constraint.toString());
// Assign the data to the FilterResults
filterResults.values = resultList;
filterResults.count = resultList.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
}
else {
notifyDataSetInvalidated();
}
}};
return filter;
}
private ArrayList<String> doPlacesSearchQuery(String query) {
ArrayList<String> retList = new ArrayList<>();
... // do my API call here
return retList;
}
}
I found my answer; I was indeed using the wrong super constructor.
public MyCustomAutoCompleteAdapter(Context context) {
super(context,
R.layout.my_custom_layout,
R.id.id_of_textview_in_my_custom_layout);
mContext = context;
}
Related
Hi in the below code Implementaing a search functionality.Gridview is used to display the grid layout .My grid layout is working fine .In that Grid I am searching by name but it is not working .
Example I have three names named as cardiology ,Ent ,Ortho if I am searching or typing ca means giving me exact one cardiology .if I type o means again showing me the cardiology the result should be ortho
can any one help me where I did the mistake
Layout:
<androidx.appcompat.widget.SearchView
android:id="#+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:queryHint="Search By Speciality"
android:iconifiedByDefault="false"
app:searchHintIcon="#drawable/ic_baseline_search_24"
app:searchIcon="#drawable/ic_baseline_search_24"
android:textSize="18sp"
android:inputType="text"
app:closeIcon="#drawable/ic_baseline_close_24"
android:background="#drawable/rectangle_border"
android:textColor="#color/black" />
Fragement.java:
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
Log.d("TAG","new Text ==>"+newText);
speclializationAdapter.getFilter().filter(newText);
return true;
}
});
Adapter:
public class SpeclializationAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private ArrayList<DataList> doctorListModels;
private ArrayList<DataList> completeList;
private SpeclializationAdapter.MyItemClickListener clickListener;
private DoctorAdapter.SelectIemClickListner selectIemClickListner;
public SpeclializationAdapter(Context context, ArrayList<DataList> doctorListModels, MyItemClickListener clickListener){
mContext=context;
this.doctorListModels=doctorListModels;
this.clickListener=clickListener;
this.completeList=doctorListModels;
this.completeList = new ArrayList<DataList>();
this.completeList.addAll(doctorListModels);
}
#Override
public int getCount() {
return doctorListModels.size();
}
#Override
public Object getItem(int position)
{
return position;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView = null;
final ImageView speclialistimage;
final TextView specialization;
final LinearLayout speclist;
if (convertView == null) {
gridView = new View(mContext);
convertView=inflater.inflate(R.layout.speclialist, null);
speclialistimage=convertView.findViewById(R.id.specilistimage);
speclist=convertView.findViewById(R.id.speclist);
specialization=convertView.findViewById(R.id.specialization);
specialization.setText(doctorListModels.get(position).getSpecialization());
// specialization.setText(speclistListFiltered.get(position).getSpecialization());
final String specliality_name=doctorListModels.get(position).getSpecialization();
if(specliality_name.equals("Cardiology")){
speclialistimage.setImageResource(R.drawable.cardiology);
}
if(specliality_name.equals("ENT specialist")){
speclialistimage.setImageResource(R.drawable.neurology);
}
if(specliality_name.equals("Orthopedics")){
speclialistimage.setImageResource(R.drawable.orthopedic);
}
final View finalGridView = gridView;
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
speclialistimage.setBackgroundResource(R.drawable.like_button);
clickListener.myItemClick(position);
}
});
}
return convertView;
}
#Override
public Filter getFilter() {
Filter filter=new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults=new FilterResults();
ArrayList<DataList> searchResult = new ArrayList<DataList>();
if (constraint != null && constraint.length() > 0) {
constraint = constraint.toString().toUpperCase();
for (int i = 0; i < completeList.size(); i++) {
if (completeList.get(i).getSpecialization().toUpperCase().contains(constraint)) {
DataList d = new DataList(completeList.get(i).getSpecialization());
searchResult.add(d);
}
}
} else {
searchResult.addAll(completeList);
}
filterResults.count = searchResult.size();
filterResults.values = searchResult;
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults filterResults) {
doctorListModels= (ArrayList<DataList>) filterResults.values;
notifyDataSetChanged();
}
};
return filter;
}
public interface MyItemClickListener{
void myItemClick(int position);
}
}
You have messed up in reference . Right now your both ArrayList i.e specialistListFiltered and doctorListModels pointing to same object . So any modification you make in one of them affects both.
Where as one list shoould contain all items and other one should contain the filtered item and only filtered List will be used with Adapter.
private ArrayList<DataList> doctorListModels;
private ArrayList<DataList> completeList;
public SpeclializationAdapter(Context context, ArrayList<DataList> doctorListModels, MyItemClickListener clickListener){
mContext=context;
this.doctorListModels=doctorListModels;
this.clickListener=clickListener;
this.completeList = new ArrayList<DataList>();
this.completeList.addAll(doctorListModels)
}
As above i have changed the name to completeList just to avoid confusion . Not you will be using complete list during filtering.
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults=new FilterResults();
ArrayList<DataList> searchResult = new ArrayList<DataList>();
if (constraint != null && constraint.length() > 0) {
constraint = constraint.toString().toUpperCase();
for (int i = 0; i < completeList.size(); i++) {
if (completeList.get(i).getSpecialization().toUpperCase().contains(constraint)) {
DataList d = new DataList(completeList.get(i).getSpecialization());
searchResult.add(d);
}
}
} else {
searchResult.addAll(completeList);
}
filterResults.count = searchResult.size();
filterResults.values = searchResult;
return filterResults;
}
PS you should be already using RecyclerView not GridView . ListView and GridView are legacy now .
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 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;
}
};
}
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
I want to add a permanent search result in autocomplete text view in android.
For ex:If i enter 'x' in the autocomplete and if it shows the list of hotels...xyz1,xyz2.etc...Then the last result must be "NOT IN LIST" value. If the user cant find their hotel then they can select NOT IN LIST option..
Even if the user types in the text that the predictive search could not give then 'NOT IN LIST' should be the only suggestion that autocomplete should give. I am new to Android.I am doing a small app.Plz help..If i have to use custom autocomplete text view then what method should i override? If so ,tell me with a method code that i have to override
Here is an AutoCompleteAdapter i used in one of my apps. I hope this solves you problem
Set the adapter from below to your AutoCompleteTextView control:
ArrayAdapter<String> adapter = new AutoCompleteAdapter(this,
R.layout.dropdown_item);
autoComplete.setAdapter(adapter);
Sample adapter:
private class AutoCompleteAdapter extends ArrayAdapter<String>
implements Filterable {
private ArrayList<String> mData;
public AutoCompleteAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
mData = new ArrayList<String>();
}
#Override
public int getCount() {
try {
return mData.size();
} catch (NullPointerException e) {
return 0;
}
}
#Override
public String getItem(int index) {
return mData.get(index);
}
#Override
public Filter getFilter() {
Filter myFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
//This shows a progress to the user in my app. you don't need to use this
handle.sendEmptyMessage(MSG_SHOW_PROGRESS);
try {
//Fill mData with your data
mData = XmlParser.searchLocations(constraint
.toString());
} catch (Exception e) {
handle.sendEmptyMessage(MSG_HIDE_PROGRESS);
}
mData.add("NOT IN LIST");
filterResults.values = mData;
filterResults.count = mData.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence contraint,
FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
handle.sendEmptyMessage(MSG_HIDE_PROGRESS);
} else {
notifyDataSetInvalidated();
handle.sendEmptyMessage(MSG_HIDE_PROGRESS);
}
}
};
return myFilter;
}
}
if (constraint != null) {
try {
for(int i=0;i<temp.size();i++)
{
if(temp.get(i).toString().startsWith(constraint.toString().toUpperCase()))
{
mData.add(temp.get(i).toString());
}
}
mData.add("SEARCH NOT THERE");
} catch (Exception e) {
}
filterResults.values = mData;
filterResults.count = mData.size();
}
return filterResults;
I have done my filtering...still it shows all the results instead of whatever i type in it...:(