2011-01-05 15 views
5

私のAutoCompleteTextViewの場合、Webサービスからデータを取得する必要があります。ちょっと時間がかかるので、UIスレッドが応答しないようにしたくないので、別のスレッドでデータを取得する必要があります。たとえば、SQLite DBからデータを取得する場合、CursorAdapterメソッド(runQueryOnBackgroundThread)を使用すると非常に簡単です。私はArrayAdapterBaseAdapterのような他のアダプターを探していましたが、何か類似のものは見つかりませんでした。別のスレッドでサービスからオートコンプリートテキストの提案を取得する

これは簡単な方法はありますか?私は単純にArrayAdapterを直接使用することはできません。提案リストは動的です。ユーザー入力に応じて常に候補リストを取得するので、プリフェッチやキャッシュには使用できません。

このトピックの例は素晴らしいでしょう!

答えて

9

EDITED:アドバイスをクリックしたときに表示されるドロップダウンを避けるための素朴な方法を追加しました。

私は私のアプリではこのような何かを:

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

私の場合、このソリューションはソフトキーボードの「削除」キーを押して入力したテキストを削除するまで、ドロップダウンメニューが表示されないので、配線されています。 – Longerian

+0

これは本当に私を助けました!どうも! – ymerdrengene

1

は問題はすべてがうまくていることであることを除いて同じソリューションを持っていた(私はデバッグするときに変数が更新される)が、オートコンプリートは

のように不気味塗りつぶし

scoを入力すると結果が表示されますが、リストに表示されません しかし、バックスペースではscoの結果が表示されます。デバッグでは、AutoCompleteTextViewのUIが更新されていないことを通知する変数のみがすべて更新されます。私はバックスペースを更新するためにトリガされ、それから以前のコンピュータリストが表示されます(新しい検索文字列の新しいリストアイテムで更新されます)。

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

すべての基本メソッドをオーバーライドし、独自のデータ構造(mSubData)を使用することで、スーパークラスがデータを保証するスレッドの安全性を含め、サブクラス化のメリットが失われました。スーパークラスのadd()/ addAll()/ clear()メソッドを使用するだけです。彼らは自動的にリスナーに通知します。そしてスレッドの安全性を保持します。 – Risadinha

関連する問題