我有一个AutoCompleteTextView,它从带有AsyncTask的API获取建议。 在onPostExecute中我创建一个新的适配器,将其设置为AutoCompleteTextView并通知数据集更改为适配器。
在TextWatcher中我执行AsyncTask。
一切正常,但每次更改适配器时都会关闭下拉列表并显示。
即使数据发生变化,如何保持下拉列表打开?
searchText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
searchPlacesTask.cancel(true);
searchPlacesTask = new SearchPlacesTask();
searchPlacesTask.execute(s.toString().replace(" ", "-"));
} else {
searchPlacesTask.cancel(true);
searchPlacesTask = new SearchPlacesTask();
searchPlacesTask.execute();
}
}
});
private class SearchPlacesTask extends AsyncTask<String, Void, PlacesAPIResult> {
@Override
protected PlacesAPIResult doInBackground(String... params) {
PlacesAPIResult result = new PlacesAPIResult();
if (params.length > 0) {
places = PlacesAPIRestMethod.placeAutocomplete(params[0], currentLocation.getLatitude(), currentLocation.getLongitude(),
500, null, result);
} else {
places = PlacesAPIRestMethod.placeSearch(currentLocation.getLatitude(), currentLocation.getLongitude(), 0, true, result);
}
return result;
}
@Override
protected void onPostExecute(PlacesAPIResult result) {
if (result.getResult() == PlacesAPIResult.OK) {
adapter = new PlaceAdapter(ChooseLocationActivity.this, R.layout.locationrow, places);
searchText.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
}
答案 0 :(得分:3)
在适配器中实现Filterable,并添加此代码。
public class ListAdapter extends ArrayAdapter<String> implements Filterable{
private List<String> listResult;
...
@Override
public Filter getFilter() {
Filter filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
// Assign the data to the FilterResults
filterResults.values = listResult;
filterResults.count = listResult.size();
}
return filterResults;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
}
else {
notifyDataSetInvalidated();
}
}};
return filter;
}
}
答案 1 :(得分:1)
我有同样的问题并以这种方式处理:
ArrayAdapter
并实现TextWatcher
的外部类,将空数据集传递给它。getFilter()
方法。那里没什么重要的。只是一个notifyDatachanged()
的存根。onProgressUpdate
中的适配器数据。也应该在onPostExecute
中工作。我的问题在这里。起初我清除了完全旧的数据,只有在那之后添加了新数据。这导致了项目下拉列表的“隐藏和显示”效果。然后我改变了清除旧数据的方式 - 我逐项删除旧数据并逐项添加新数据。这解决了不必要的影响。在你的情况下,我建议移动PlaceAdapter
的构造并从onPostExecute
设置适配器,并执行以下操作:
@Override
protected void onPostExecute(PlacesAPIResult result) {
if (result.getResult() == PlacesAPIResult.OK) {
//TODO: iterate adapter's data and remove every item
//TODO: iterate `places` collection and add each item to adapter's data
adapter.notifyDataSetChanged();
}
}
答案 2 :(得分:0)
AutoCompleteTextView.setAdapter()
方法接受继承ListAdapter
和Filterable
接口的类的实例。
Filterable
界面是您问题的关键。
当您在AutoCompleteTextView
中输入文字时,它会使用Filter
方法返回的Filterable.getFilter()
来过滤下拉列表中的项目。
如果您的PlaceAdapter
继承自ArrayAdapter
,那么您应该注意到ArrayAdapter
已经实现了Filterable
界面,getFilter()
方法返回ArrayFilter
performFiltering(CharSequence prefix)
方法获取ArrayAdapter
的当前项,使用item.toString().toLowerCase()
将其转换为小写字符串,并仅过滤那些包含以prefix.toString().toLowerCase()
开头的字词的字符串。
接下来我注意到,如果Filter.performFiltering()
方法返回带有FilterResults
的{{1}},则下拉列表会隐藏。
因此,如果您没有使用执行FilterResults.count == 0
的自定义过滤器覆盖ArrayAdapter.getFilter()
方法,那么由于SearchPlacesTask
返回零结果并显示Filter.performFiltering()
,您最终会隐藏下拉列表1}}分配新适配器并调用SearchPlacesTask.onPostExecute()
。
最佳选择是不要使用notifyDataSetChanged()
并在AsyncTask
内调用您的API方法:
Filter.performFiltering()
如果您被迫使用public class PlacesAdapter extends ArrayAdapter<String> {
private final List<Place> items = new ArrayList<Place>();
// other code
// ...
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
String query = constraint != null ? constraint.toString() : "";
List<Place> places;
PlacesAPIResult result = new PlacesAPIResult();
if (query.isEmpty()) {
places = PlacesAPIRestMethod
.placeSearch(currentLocation.getLatitude(),
currentLocation.getLongitude(), 0, true, result);
} else {
places = PlacesAPIRestMethod.placeAutocomplete(query,
currentLocation.getLatitude(), currentLocation.getLongitude(),
500, null, result);
}
if (result.getResult() == PlacesAPIResult.OK) {
filterResults.values = places;
filterResults.count = places.size();
}
return filterResults;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<Place> places = (List<Place>) results.values;
if (places != null) {
items.clear();
items.addAll(places);
notifyDataSetChanged();
}
else {
notifyDataSetInvalidated();
}
}
};
}
}
,那么您可以在AsyncTask
SearchPlacesTask
中执行Filter.performFiltering()
同步等待任务完成并返回new SearchPlacesTask().execute(query).get()
的结果方法。
Filter.performFiltering()
方法,因此您不必担心API方法的异步执行。
Filter.performFiltering()
方法,这是您应该更新适配器并调用Filter.publishResults()
的地方。
notifyDataSetChanged()
管理重复请求,因此在适配器中实施AutoCompleteTextView
是正确使用Filterable
的唯一正确方法。 / p>