2012-06-13 54 views
3

我有一个AutoCompleteTextView从API获取建议与AsyncTask。 在onPostExecute我创建一个新的适配器,将其设置为AutoCompleteTextView并通知数据集更改到适配器。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

嗨,我面临同样的问题,但无法解决。请让我知道你是否能够解决这个问题。 – Zoombie

+0

现在我面临同样的问题。如果你有解决方案,请让我知道 –

回答

1

我有同样的问题,这样处理:

  1. 创建扩展ArrayAdapter并实现TextWatcher传递一个空的数据收集到它的外部类。
  2. 以类似的方式启动工作线程。
  3. 实施getFilter()方法。那里没有重要的事情。只是一个存根notifyDatachanged()
  4. 更新了适配器的数据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(); 
     } 
    } 
3

实现了转接器可过滤,并添加该代码。

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; 
    } 
} 
+0

我不能相信这个工作......我不明白,但你只是救了我几个小时的额外工作,非常感谢!为了记录,每当我想刷新适配器时,我都给listResult赋值。 – Analizer

+0

这是如何工作的? Dropdown如何膨胀?你能解释一下吗?另外,如何获得下拉菜单中的itemclick? – KarthikKPN

0

AutoCompleteTextView.setAdapter()方法接受类继承ListAdapterFilterable接口的实例。 Filterable接口是你的问题的关键。

当您在AutoCompleteTextView中键入文本时,它使用从Filterable.getFilter()方法返回的Filter过滤下拉列表中的项目。

如果您从ArrayAdapterPlaceAdapter继承,那么你应该注意到ArrayAdapter已经实现Filterable接口和getFilter()方法返回ArrayFilterperformFiltering(CharSequence prefix)方法利用ArrayAdapter经常项目,把它们只有小写与item.toString().toLowerCase()字符串和过滤器这些人具有以prefix.toString().toLowerCase()开头的单词。

接下来我注意到,如果Filter.performFiltering()方法返回FilterResultsFilterResults.count == 0然后下拉列表隐藏。

所以,如果你不重写ArrayAdapter.getFilter()方法与自定义过滤器,执行你SearchPlacesTask那么你就结束了下拉列表中隐藏,因为Filter.performFiltering()返回结果为零,并表示当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那么您可以在Filter.performFiltering()new SearchPlacesTask().execute(query).get()执行SearchPlacesTask同步等待,直到任务完成并从Filter.performFiltering()方法返回结果。

Filter.performFiltering()在工作线程中调用方法,因此您不必担心异步执行API方法。

Filter.publishResults()方法在UI线程中调用,这是您应该更新适配器并调用notifyDataSetChanged()的地方。

AutoCompleteTextView管理的一再要求,当用户更改文本更快然后新的结果加载并取消之前的请求,以便实现在适配器Filterable是正确使用AutoCompleteTextView的唯一正确途径。

相关问题