Get filtered array size in AutoCompleteTextview
我正在研究用户可以在其中搜索数据的项目。为此,我实现了
1 2 3 4 | autoComplete.setAdapter(new ArrayAdapter<String>(CheckRiskActivity.this, R.layout.auto_text_row, druglist)); autoComplete.setThreshold(1); //druglist is my arraylist |
文本更改侦听器如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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) { } }); |
说明:如果我的初始数组大小为100,并且用户键入\\'a \\',那么我想获取过滤后的数组的大小。
注意:我已经尝试了
您无法在
我将提供2种相似的方法:使用单独的类和仅使用1个类。
方法1:
您的适配器应如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 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(); } } } }; } |
一个用于通知您何时过滤将完成的界面:
1 2 3 4 | public interface FilterListeners { void filteringFinished(int filteredItemsCount); } |
您可以使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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); } } |
方法2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 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); } } |
在自动完成输入字段中输入内容并被过滤时,将调用
更新(Trie搜索):
我创建了一个Github项目,其中有一个使用Trie搜索算法来大大提高自动完成性能的简单示例。
https://github.com/saqada/android-AutoCompleteWithTrie
根据Ayaz Alifov的回答,您无法在
但是我用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | editText.addTextChangedListener( new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } private Timer timer=new Timer(); private final long DELAY = 1000; // milliseconds @Override public void afterTextChanged(final Editable s) { timer.cancel(); timer = new Timer(); timer.schedule( new TimerTask() { @Override public void run() { // adapter.getCount() will give you the correct item's counts Log.d(TAG,"run: afterTextChanged" + adapter.getCount()); } }, DELAY ); } } ); |
编辑:2019年9月5日
您还可以通过设置
1 2 3 4 5 6 7 | adapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { super.onChanged(); Log.d(TAG,"onChanged:" + adapter.getCount()); } }); |
这样,
基本上,我们必须在Adapter类中实现Filterable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | public class DrugListAdapter extends BaseAdapter implements Filterable { Context context; LayoutInflater inflater; drugsFilter drugsFilter; List<Drug> drugList = new ArrayList<>(); private List<Drug> drugListOrig; public DrugListAdapter(Context context, List<Drug> drugList) { super(); this.context = context; this.drugList = drugList; this.drugListOrig = new ArrayList<>( drugList); inflater = LayoutInflater.from(context); } public void resetData() { drugList = drugListOrig; } @Override public int getCount() { return drugList.size(); } @Override public Drug getItem(int position) { return drugList.get(position); } @Override public long getItemId(int id) { return id; } private class ViewHolder { TextView mVendorName; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; ViewHolder viewHolder; Drug item = drugList.get(position); if (view == null) { viewHolder = new ViewHolder(); view = inflater.inflate(R.layout.item_drug, parent, false); viewHolder.mVendorName = (TextView) view .findViewById(R.id.item_drug_drug_name); view.setTag(viewHolder); } else { viewHolder = (ViewHolder) view.getTag(); } viewHolder.mVendorName.setText(item.getDrug_name()); return view; } @Override public Filter getFilter() { if (drugsFilter == null) { drugsFilter = new DrugsFilter(); } return drugsFilter; } public class DrugsFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); // We implement here the filter logic if (constraint == null || constraint.length() == 0) { // No filter implemented we return all the list results.values = drugListOrig; results.count = drugListOrig.size(); } else { // We perform filtering operation List<Drug> sList = new ArrayList<>(); for (Drug p : drugList) { if (p.getDrug_name().toUpperCase() .startsWith(constraint.toString().toUpperCase())) sList.add(p); } results.values = sList; results.count = sList.size(); } return results; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { if (results.count == 0) notifyDataSetInvalidated(); else { drugList = (List<Drug>) results.values; notifyDataSetChanged(); } } } |
} ??
此部分用于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | String m; mDrugEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (count < before) { adapter.resetData(); adapter.notifyDataSetChanged(); } adapter.getFilter().filter(s.toString()); } @Override public void beforeTextChanged(CharSequence s, int start, int before, int count) { if (s.length() == 0 || s.length() == 1) { mDrugEditText.invalidate(); } if (s.length() == 3) { if (mDrugEditText .isPerformingCompletion()) { return; } adapter.resetData(); adapter.notifyDataSetChanged(); } } @Override public void afterTextChanged(Editable s) { m = s.toString(); adapter.getFilter().filter(s.toString()); } }); |
萨卡达的答案是一个很好的方法,但是,下面的答案使我的情况下表现更好。
1 2 3 4 | autoCompleteTextViewCheckRisk.setAdapter(new ArrayAdapter<String> (CheckRiskActivity.this, R.layout.auto_text_row, druglist)); //druglist is the Arraylist of String. autoCompleteTextViewCheckRisk.setThreshold(1); |
文本更改侦听器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | autoCompleteTextViewCheckRisk.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) { filter(druglist, s.toString()); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } }); |
过滤方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | private void filter(ArrayList<String> originalArrayList, String query) { query = query.toLowerCase(); filteredArrayList.clear(); //filtered arraylist is also Arraylist of String, Just declared as global for (String itemName : originalArrayList) { final String text = itemName.toLowerCase(); if (text.startsWith(query)) { filteredArrayList.add(itemName); } } if (filteredArrayList.size() == 0) { Log.i(TAG,"filter: No data found"); } } |
我假设您已通过android / java中提供的基本搜索选项,但对结果不满意。
如果您不想在每次文本更改时都遍历整个列表,则唯一的方法是实现一个能做到这一点的数据结构。
显而易见的解决方案是trie.read this以获得有关trie的想法
现在,这适用于在搜索之前对数据进行预处理的概念。由于您的元素有限-不会花费太多时间,并且可以在页面加载时完成。
步骤-
-处理和索引加载中的所有元素。将索引放在k进制树上(它将是32进制,每个字符将是一个字母)。
-更改文本时-遍历该节点并获得计数。将花费O(1)。
我相信这是最快的。
如果您将单词编入索引或仅需从头开始,则上述方法将效果最好。