Adding a permanent search title in autocomplete textview android - android

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...:(

Related

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 can i make a live query field in my android app that queries to my MYSQL database without the need to press search

I have a working search function that inserts search results into a spinner, but i want it to be live without the need to press a search button just like google.
Something like this:
Well, first of all, you need to use an AutoCompleteTextView, that triggers a filter each time that the text change, and show the suggestions exactly as the image that you attached.
Then, you must be your custom adapter and add it to your view in your onCreate function of your activity:
protected void onCreate(Bundle savedInstanceState) {
...
AutomaticSearchAdapter adapter = new AutomaticSearchAdapter(this, new ArrayList<CustomObject>(), "");
listView = (AutoCompleteTextView) findViewById(R.id.search_complete);
listView.setThreshold(1);
listView.setAdapter(adapter);
...
}
Here is a template of how you can build your custom adapter, that load data from any API and suggest according to your own filtering criteria
public class AutomaticSearchAdapter extends ArrayAdapter implements AsyncResponse, Filterable {
private ArrayList<ContactItem> realList; // The list that will be shown
private ArrayList<CustomObject> results = new ArrayList<CustomObject> (); // A list with all data from your API
private Filter mFilter = new Filter(){
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(constraint != null) {
String constraintTrim = ContactSearchAdapter.toPlain(constraint.toString()).trim().toLowerCase();
// When te user introduces at least 3 characteres, get data from your API
if (constraintTrim.length() == 3) {
// Call Here to you API, and populate results
}
ArrayList<CustomObject> suggestions = new ArrayList<CustomObject> ();
for (CustomObject object : results) {
if(/*some condition on your downloaded datum */) {
suggestions.add(object);
}
}
filterResults.values = suggestions;
filterResults.count = suggestions.size();
}
return filterResults;
}
#Override
protected void publishResults(CharSequence contraint, FilterResults results) {
if(results == null){
return;
}
try {
realList.clear();
if (results.values != null){
realList.addAll((List<CustomObject>) results.values);
}
notifyDataSetChanged();
}catch ( Exception e) {
}
}
};
public int getCount() {
return realList.size();
}
#Override
public Object getItem(int position) {
try {
if (realList.size() > 0 ) {
return realList.get(position);
}else {
return null;
}
}catch (Exception ex) {
return null;
}
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// HERE MUST BE YOUR CUSTOM getView FROM YOUR LIST
// YOU CAN LEARN MORE ABOUT http://androidexample.com/How_To_Create_A_Custom_Listview_-_Android_Example/index.php?view=article_discription&aid=67
return convertView;
}
#Override
public void postStart() {
//Nothing to do.
}
#Override
public Filter getFilter() {
return mFilter;
}
}
Of course, you will need refactor the code above for your own requirements.
I bevieve what you need is an onTextChanged listener take a look here https://developer.android.com/reference/android/text/TextWatcher.html

Android Custom autocompletetextview freezes on backspace click

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

AutoCompleteTextView not populating with selected item

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

List View Filter Android

I have created a list view in android and I want to add edit text above the list and when the user enter text the list will be filtered according to user input
can anyone tell me please if there is a way to filter the list adapter in android ?
Add an EditText on top of your listview in its .xml layout file.
And in your activity/fragment..
lv = (ListView) findViewById(R.id.list_view);
inputSearch = (EditText) findViewById(R.id.inputSearch);
// Adding items to listview
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.product_name, products);
lv.setAdapter(adapter);
inputSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
MainActivity.this.adapter.getFilter().filter(cs);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { }
#Override
public void afterTextChanged(Editable arg0) {}
});
The basic here is to add an OnTextChangeListener to your edit text and inside its callback method apply filter to your listview's adapter.
EDIT
To get filter to your custom BaseAdapter you"ll need to implement Filterable interface.
class CustomAdapter extends BaseAdapter implements Filterable {
public View getView(){
...
}
public Integer getCount()
{
...
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
arrayListNames = (List<String>) results.values;
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
ArrayList<String> FilteredArrayNames = new ArrayList<String>();
// perform your search here using the searchConstraint String.
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mDatabaseOfNames.size(); i++) {
String dataNames = mDatabaseOfNames.get(i);
if (dataNames.toLowerCase().startsWith(constraint.toString())) {
FilteredArrayNames.add(dataNames);
}
}
results.count = FilteredArrayNames.size();
results.values = FilteredArrayNames;
Log.e("VALUES", results.values.toString());
return results;
}
};
return filter;
}
}
Inside performFiltering() you need to do actual comparison of the search query to values in your database. It will pass its result to publishResults() method.
Implement your adapter Filterable:
public class vJournalAdapter extends ArrayAdapter<JournalModel> implements Filterable{
private ArrayList<JournalModel> items;
private Context mContext;
....
then create your Filter class:
private class JournalFilter extends Filter{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults result = new FilterResults();
List<JournalModel> allJournals = getAllJournals();
if(constraint == null || constraint.length() == 0){
result.values = allJournals;
result.count = allJournals.size();
}else{
ArrayList<JournalModel> filteredList = new ArrayList<JournalModel>();
for(JournalModel j: allJournals){
if(j.source.title.contains(constraint))
filteredList.add(j);
}
result.values = filteredList;
result.count = filteredList.size();
}
return result;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count == 0) {
notifyDataSetInvalidated();
} else {
items = (ArrayList<JournalModel>) results.values;
notifyDataSetChanged();
}
}
}
this way, your adapter is Filterable, you can pass filter item to adapter's filter and do the work.
I hope this will be helpful.
In case anyone are still interested in this subject, I find that the best approach for filtering lists is to create a generic Filter class and use it with some base reflection/generics techniques contained in the Java old school SDK package. Here's what I did:
public class GenericListFilter<T> extends Filter {
/**
* Copycat constructor
* #param list the original list to be used
*/
public GenericListFilter (List<T> list, String reflectMethodName, ArrayAdapter<T> adapter) {
super ();
mInternalList = new ArrayList<>(list);
mAdapterUsed = adapter;
try {
ParameterizedType stringListType = (ParameterizedType)
getClass().getField("mInternalList").getGenericType();
mCompairMethod =
stringListType.getActualTypeArguments()[0].getClass().getMethod(reflectMethodName);
}
catch (Exception ex) {
Log.w("GenericListFilter", ex.getMessage(), ex);
try {
if (mInternalList.size() > 0) {
T type = mInternalList.get(0);
mCompairMethod = type.getClass().getMethod(reflectMethodName);
}
}
catch (Exception e) {
Log.e("GenericListFilter", e.getMessage(), e);
}
}
}
/**
* Let's filter the data with the given constraint
* #param constraint
* #return
*/
#Override protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<T> filteredContents = new ArrayList<>();
if ( constraint.length() > 0 ) {
try {
for (T obj : mInternalList) {
String result = (String) mCompairMethod.invoke(obj);
if (result.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
filteredContents.add(obj);
}
}
}
catch (Exception ex) {
Log.e("GenericListFilter", ex.getMessage(), ex);
}
}
else {
filteredContents.addAll(mInternalList);
}
results.values = filteredContents;
results.count = filteredContents.size();
return results;
}
/**
* Publish the filtering adapter list
* #param constraint
* #param results
*/
#Override protected void publishResults(CharSequence constraint, FilterResults results) {
mAdapterUsed.clear();
mAdapterUsed.addAll((List<T>) results.values);
if ( results.count == 0 ) {
mAdapterUsed.notifyDataSetInvalidated();
}
else {
mAdapterUsed.notifyDataSetChanged();
}
}
// class properties
private ArrayAdapter<T> mAdapterUsed;
private List<T> mInternalList;
private Method mCompairMethod;
}
And afterwards, the only thing you need to do is to create the filter as a member class (possibly within the View's "onCreate") passing your adapter reference, your list, and the method to be called for filtering:
this.mFilter = new GenericFilter<MyObjectBean> (list, "getName", adapter);
The only thing missing now, is to override the "getFilter" method in the adapter class:
#Override public Filter getFilter () {
return MyViewClass.this.mFilter;
}
All done! You should successfully filter your list - Of course, you should also implement your filter algorithm the best way that describes your need, the code bellow is just an example.. Hope it helped, take care.

Categories

Resources