我想通过从RESTful Web服务获取列表来定期更改AutoCompleteTextview提供的建议,但无法使其顺利运行。我设置了一个硬编码的建议列表,以确保它正常工作:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, new String[] {"Hi", "Ho"});
speciesName.setAdapter(adapter);//my autocomplete tv
我在textview上有一个TextWatcher,当文本发生变化时会启动一个非阻塞调用来获取新的建议列表 - 这个获得新列表的部分工作正常。然后我想重置适配器,如下所示:
public void setOptionsAndUpdate(String[] options) {
Log.d(TAG, "setting options");
//speciesName.setAdapter((ArrayAdapter<String>)null);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, options);
speciesName.setAdapter(adapter);
}
此方法被调用,但不起作用 - 尽管调用setAdapter
,建议列表仍然消失或显示的建议保持不变。
这甚至是正确的方法吗?我查看了SimpleCursorAdapter
,但看不到如何将我的网络服务注册为内容提供商。 (它的格式为http://www.blah.com/query?term=XX,其中XX是我的应用程序的输入,响应是JSON字符串数组。)
答案 0 :(得分:36)
在动态添加和更改适配器中的数据时,我没有运气使用adapter.notifyDataSetChanged()。在我的情况下,我异步地击中外部api并定期获取完成数据列表。
此代码清除适配器,并按预期添加新数据。但是,我必须调用getFilter()。Filter方法来强制显示数据。另外,我必须根据AutocompleteTextView中的当前文本显式过滤,因为我的api调用是异步的。
adapter.clear();
for (Map<String, String> map : completions) {
adapter.add(map.get("name"));
}
//Force the adapter to filter itself, necessary to show new data.
//Filter based on the current text because api call is asynchronous.
adapter.getFilter().filter(autocompleteTextView.getText(), null);
答案 1 :(得分:23)
使用Google Map API中的远程数据填充AutoCompleteTextView here,有一个关于此主题的非常好的教程。
如果您需要缓存版本,我会从here检索它。 原始教程已被删除,但基本上您需要使用自定义过滤器编写ArrayAdapter,其方式与下面所示类似,并将其分配给AutoCompleteTextView。
注意:您需要实现一个方法autocomplete(),该方法执行同步获取和返回自动完成项所需的任何操作。由于在后台线程中调用过滤器,因此不会阻止主UI线程。
private class PlacesAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {
private ArrayList<String> resultList;
public PlacesAutoCompleteAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
@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 = autocomplete(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;
}
}
答案 2 :(得分:18)
这是我更新AutoCompleteTextView的方式:
String[] data = terms.toArray(new String[terms.size()]); // terms is a List<String>
ArrayAdapter<?> adapter = new ArrayAdapter<Object>(activity, android.R.layout.simple_dropdown_item_1line, data);
keywordField.setAdapter(adapter); // keywordField is a AutoCompleteTextView
if(terms.size() < 40) keywordField.setThreshold(1);
else keywordField.setThreshold(2);
现在当然,这是静态的,并不处理无线的建议,但是,我还建议您在将更改分配给AutoCompleteTextView后通知适配器:
adapter.notifyDataSetChanged();
希望这有帮助。
-serkan
答案 3 :(得分:2)
由于我无法添加评论,因此我给出了新答案 无需清除适配器或调用adapter.getFilter()。filter(...)... 要动态更新AutoCompleteTextView适配器,只需将新项添加到适配器并再次添加setAdapter。对于原始问题中给出的示例,我尝试了以下它并且它可以工作(下面的代码没有显示适配器的初始设置,因为这里的多个答案涵盖了。这只是动态更新适配器)。适配器更新可以与更新与ArrayAdapter关联的List的代码一起使用。
adapter.add(String newSuggestion); // this goes inside a loop for adding multiple suggestions
speciesName.setAdapter(adapter) ; // speciesName is an AutoCompleteTextView as given in the original question.
答案 4 :(得分:2)
我找到的用于更新适配器的最佳解决方案:
Editable text = autocomplete.getText();
autocomplete.setText(text);
autocomplete.setSelection(text.length());
工作方式:
我们将 autoCompleteTextView 的文本设置为其当前文本,以便适配器通知数据已更改并更新listViews的内容。
但是通过这种技巧,光标将移动到edittext的开头。因此我们使用autocomplete.setSelection(text.length())
将光标移到末尾。
像魅力一样工作!
编辑:
此外,您必须直接在clear()
而不是add()
上使用remove()
,ArrayAdapter
和ArrayList
方法。