I am working on the project in which user can search data. For that, I have implemented AutoCompleteTextView
.
autoComplete.setAdapter(new ArrayAdapter<String>(CheckRiskActivity.this,
R.layout.auto_text_row, druglist));
autoComplete.setThreshold(1);
//druglist is my arraylist
Text change listener is as below:
autoComplete.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
// here I want to get the size of filtered array list every time when the user adds any character.
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
});
Explanation: If my initial array size is 100 and if the user types 'a', then I want to get the size of filtered array.
Note: I have tried autoComplete.getAdapter().getCount();
but it gives the actual result after adding one more character.
You cannot get correct filtered items' count in TextWatcher
, because filtering usually takes longer time than TextWatcher
event listeners. Therefore you get incorrect autoComplete.getAdapter().getCount()
in afterTextChanged()
. I would recommend to use custom listener which will be called every time when filtered items are changed.
I will provide 2 similar approaches: using separate classes and using only 1 class.
APPROACH 1: Your adapter should look like:
import android.content.Context;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import java.util.ArrayList;
import java.util.List;
public class AutoCompleteAdapter extends ArrayAdapter
{
private List<String> tempItems;
private List<String> suggestions;
private FilterListeners filterListeners;
public AutoCompleteAdapter(Context context, int resource, List<String> items)
{
super(context, resource, 0, items);
tempItems = new ArrayList<>(items);
suggestions = new ArrayList<>();
}
public void setFilterListeners(FilterListeners filterFinishedListener)
{
filterListeners = filterFinishedListener;
}
@Override
public Filter getFilter()
{
return nameFilter;
}
Filter nameFilter = new Filter()
{
@Override
protected FilterResults performFiltering(CharSequence constraint)
{
if (constraint != null)
{
suggestions.clear();
for (String names : tempItems)
{
if (names.toLowerCase().startsWith(constraint.toString().toLowerCase()))
{
suggestions.add(names);
}
}
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<String> filterList = (ArrayList<String>) results.values;
if (filterListeners != null && filterList!= null)
filterListeners.filteringFinished(filterList.size());
if (results != null && results.count > 0)
{
clear();
for (String item : filterList)
{
add(item);
notifyDataSetChanged();
}
}
}
};
}
An interface which is used to inform you when filtering will be finished:
public interface FilterListeners
{
void filteringFinished(int filteredItemsCount);
}
And you can use it:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.AutoCompleteTextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity implements FilterListeners
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AutoCompleteTextView autoComplete = (AutoCompleteTextView) findViewById(R.id.autoComplete);
autoComplete.setThreshold(1);
List<String> stringList = new ArrayList<>();
stringList.add("Black");
stringList.add("White");
stringList.add("Yellow");
stringList.add("Blue");
stringList.add("Brown");
final AutoCompleteAdapter adapter = new AutoCompleteAdapter(this, android.R.layout.simple_list_item_1, stringList);
adapter.setFilterListeners(this);
autoComplete.setAdapter(adapter);
}
@Override
public void filteringFinished(int filteredItemsCount)
{
Log.i("LOG_TAG", " filteringFinished count = " + filteredItemsCount);
}
}
APPROACH 2:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Filter;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final AutoCompleteTextView autoComplete = (AutoCompleteTextView) findViewById(R.id.autoComplete);
autoComplete.setThreshold(1);
final List<String> stringList = new ArrayList<>();
stringList.add("Black");
stringList.add("White");
stringList.add("Yellow");
stringList.add("Blue");
stringList.add("Brown");
final ArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, stringList)
{
private List<String> tempItems = stringList;
private List<String> suggestions = new ArrayList<>();
@Override
public Filter getFilter()
{
return nameFilter;
}
Filter nameFilter = new Filter()
{
@Override
protected FilterResults performFiltering(CharSequence constraint)
{
if (constraint != null)
{
suggestions.clear();
for (String names : tempItems)
{
if (names.toLowerCase().startsWith(constraint.toString().toLowerCase()))
{
suggestions.add(names);
}
}
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<String> filterList = (ArrayList<String>) results.values;
filteringFinished(filterList.size());
if (results != null && results.count > 0)
{
clear();
for (String item : filterList)
{
add(item);
notifyDataSetChanged();
}
}
}
};
};
autoComplete.setAdapter(arrayAdapter);
}
private void filteringFinished(int filteredItemsCount)
{
Log.i("LOG_TAG", " filteringFinished count = " + filteredItemsCount);
}
}
filteringFinished()
method will be called when you enter something to an autocomplete input field and it gets filtered.
UPDATE (Trie Search):
I have created a Github project with a simple example of using Trie search algorithm to increase autocomplete performance very much.