6

AutoCompleteTextViewの場合、Web サービスからデータを取得する必要があります。少し時間がかかる可能性があるため、UI スレッドが応答しないようにしたくないため、別のスレッドでデータをフェッチする必要があります。たとえば、SQLite DB からデータを取得する場合、CursorAdapterメソッド -を使用すると非常に簡単に実行できrunQueryOnBackgroundThreadます。ArrayAdapter、のような他のアダプターを探しましBaseAdapterたが、同様のものは見つかりませんでした...

これを達成する簡単な方法はありますか?提案リストは動的であるため、単純にArrayAdapter直接使用することはできません。ユーザー入力に応じて常に提案リストを取得するため、事前に取得してキャッシュしてさらに使用することはできません...

誰かがこのトピックに関するいくつかのヒントや例を提供できれば、それは素晴らしいことです!

4

3 に答える 3

10

上記のアプローチでは、非常に速く入力するときにもこれらの問題がありました。結果のフィルタリングがフィルター クラスによって非同期的に行われるためだと思います。そのため、フィルタリングの実行中に UI スレッドでアダプターの ArrayList を変更すると問題が発生する可能性があります。

http://developer.android.com/reference/android/widget/Filter.html

ただし、次のアプローチではすべて正常に機能しました。

public class MyActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        MyAdapter myAdapter = new MyAdapter(this, android.R.layout.simple_dropdown_item_1line);

        AutoCompleteTextView acTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
        acTextView.setAdapter(myAdapter);
    }
}

public class MyAdapter extends ArrayAdapter<MyObject> {
    private Filter mFilter;

    private List<MyObject> mSubData = new ArrayList<MyObject>();
    static int counter=0;

    public MyAdapter(Context context, int textViewResourceId) {
      super(context, textViewResourceId);
      setNotifyOnChange(false);

      mFilter = new Filter() {
        private int c = ++counter;
        private List<MyObject> mData = new ArrayList<MyObject>();

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
          // This method is called in a worker thread
          mData.clear();

          FilterResults filterResults = new FilterResults();
          if(constraint != null) {
            try {
              // Here is the method (synchronous) that fetches the data
              // from the server      
              URL url = new URL("...");
              URLConnection conn = url.openConnection();
              BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
              String line = "";

              while ((line = rd.readLine()) != null) {
                      mData.add(new MyObject(line));
              }
            }
            catch(Exception e) {
            }

            filterResults.values = mData;
            filterResults.count = mData.size();
          }
          return filterResults;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence contraint, FilterResults results) {
          if(c == counter) {
            mSubData.clear();
              if(results != null && results.count > 0) {
                ArrayList<MyObject> objects = (ArrayList<MyObject>)results.values;
                for (MyObject v : objects)
                  mSubData.add(v);

                notifyDataSetChanged();
              }
              else {
                notifyDataSetInvalidated();
              }
          }
        }
    };
  }

  @Override
  public int getCount() {
    return mSubData.size();
  }

  @Override
  public MyObject getItem(int index) {
    return mSubData.get(index);
  }

  @Override
  public Filter getFilter() {
    return mFilter;
  }
}
于 2011-11-01T17:49:32.560 に答える
9

編集済み:提案をクリックしたときにドロップダウンが表示されないようにする単純な方法を追加しました。

私は自分のアプリで次のようなことをします:

private AutoCompleteTextView mSearchbar;
private ArrayAdapter<String> mAutoCompleteAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    mAutoCompleteAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line);
    mSearchbar = (AutoCompleteTextView) findViewById(R.id.searchbar);
    mSearchbar.setThreshold(3);
    mSearchbar.setAdapter(mAutoCompleteAdapter);
    mSearchbar.addTextChangedListener(new TextWatcher() {

        private boolean shouldAutoComplete = true;

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            shouldAutoComplete = true;
            for (int position = 0; position < mAutoCompleteAdapter.getCount(); position++) {
                if (mAutoCompleteAdapter.getItem(position).equalsIgnoreCase(s.toString())) {
                    shouldAutoComplete = false;
                    break;
                }
            }

        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            if (shouldAutoComplete) {
                new DoAutoCompleteSearch().execute(s.toString());
            }
        }
    }
}

private class DoAutoCompleteSearch extends AsyncTask<String, Void, ArrayList<String>> {
    @Override
    protected ArrayList<String> doInBackground(String... params) {
        ArrayList<String> autoComplete = new ArrayList<String>();
        //do autocomplete search and stuff.
        return autoComplete;
    }

    @Override
    protected void onPostExecute(ArrayList<String> result) {
        mAutoCompleteAdapter.clear();
        for (String s : result)
            mAutoCompleteAdapter.add(s);
    }
}
于 2011-01-20T13:19:38.367 に答える
1

問題がすべて問題ないことを除いて同じ解決策がありました(変数はデバッグ時に更新されます)が、オートコンプリートは次のように奇妙に塗りつぶされます

sco と入力すると結果が表示されますが、リストには表示されませんが、バックスペースを押すと sco の結果が表示されます。デバッグでは、すべての変数が更新されますが、AutoCompleteTextView の UI が更新されていないことがわかります。バックスペースすると、更新がトリガーされ、以前のコンピューターリストが表示され、その後、新しい検索文字列の新しいリスト項目で更新されます。誰かがこの問題に遭遇しましたか?

于 2011-09-28T15:59:42.953 に答える