AutoCompleteTextView隐藏并显示适配器更改的下拉列表

时间:2012-06-13 07:54:15

标签: android

我有一个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();
        }
    }
}

3 个答案:

答案 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)

我有同样的问题并以这种方式处理:

  1. 创建了一个扩展ArrayAdapter并实现TextWatcher的外部类,将空数据集传递给它。
  2. 以类似的方式启动工作线程。
  3. 已实施getFilter()方法。那里没什么重要的。只是一个notifyDatachanged()的存根。
  4. 更新了onProgressUpdate中的适配器数据。也应该在onPostExecute中工作。我的问题在这里。起初我清除了完全旧的数据,只有在那之后添加了新数据。这导致了项目下拉列表的“隐藏和显示”效果。然后我改变了清除旧数据的方式 - 我逐项删除旧数据并逐项添加新数据。这解决了不必要的影响。
  5. 在你的情况下,我建议移动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()方法接受继承ListAdapterFilterable接口的类的实例。 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方法的异步执行。

在UI线程中调用

Filter.performFiltering()方法,这是您应该更新适配器并调用Filter.publishResults()的地方。

当用户更快地更改文本然后加载新结果并取消之前的请求时,

notifyDataSetChanged()管理重复请求,因此在适配器中实施AutoCompleteTextView是正确使用Filterable的唯一正确方法。 / p>

相关问题