4

AsyncTask を使用して API から提案を取得する AutoCompleteTextView があります。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();
        }
    }
}
4

3 に答える 3

4

アダプタに 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;
    }
}
于 2014-03-10T16:31:19.120 に答える
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();
        }
    }
于 2012-11-08T03:27:04.263 に答える
0

AutoCompleteTextView.setAdapter()ListAdapterメソッドは、継承およびFilterableインターフェース するクラスのインスタンスを受け入れます。Filterableインターフェイスが問題の鍵です。

テキストを入力すると、メソッドから返されたテキストをAutoCompleteTextView使用して、ドロップダウン リストの項目がフィルター処理されます。FilterFilterable.getFilter()

PlaceAdapterが から継承されている場合は、メソッドが の現在のアイテムを受け取り、それらを で小文字の文字列に変換し、 で始まる単語を持つものだけをフィルタリングすることを返すインターフェイスとメソッドを既に実装しているArrayAdapterことに気付くはずです。ArrayAdapterFilterablegetFilter()ArrayFilterperformFiltering(CharSequence prefix)ArrayAdapteritem.toString().toLowerCase()prefix.toString().toLowerCase()

Filter.performFiltering()次に、メソッドが返さFilterResultsれた場合FilterResults.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実行できます。SearchPlacesTaskFilter.performFiltering()new SearchPlacesTask().execute(query).get()Filter.performFiltering()

Filter.performFiltering()メソッドはワーカー スレッドで呼び出されるため、API メソッドの非同期実行について心配する必要はありません。

Filter.publishResults()メソッドは UI スレッドで呼び出され、これはアダプタを更新して を呼び出す場所ですnotifyDataSetChanged()

AutoCompleteTextViewは、ユーザーがテキストをより速く変更したときに繰り返されるリクエストを管理し、新しい結果が読み込まれ、以前のリクエストをキャンセルするためFilterable、アダプターに実装することが を正しく使用する唯一の正しい方法AutoCompleteTextViewです。

于 2015-07-19T16:33:52.527 に答える