2011-01-05 56 views
5

對於我的AutoCompleteTextView我需要從Web服務中獲取數據。因爲它可能需要一點時間我不希望UI線程不響應,所以我需要以某種方式在單獨的線程中獲取數據。例如,在從SQLite DB獲取數據時,使用CursorAdapter方法 - runQueryOnBackgroundThread可以非常容易地完成。我正在四處尋找其他適配器,如ArrayAdapter,BaseAdapter,但找不到類似的東西...在單獨的線程中從服務獲取AutoCompleteTextView建議

有沒有簡單的方法如何實現這一目標?我不能直接簡單地使用ArrayAdapter,因爲建議列表是動態的 - 我總是根據用戶輸入獲取建議列表,因此無法預取和緩存以供進一步使用...

如果有人可以提供一些提示或關於這個主題的例子 - 會很棒!

回答

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

這個解決方案在我的情況下有一些問題,直到我按下軟鍵盤上的'刪除'鍵來刪除輸入的文本時,下拉菜單才顯示出來,它是如此的有線連接。 – Longerian 2013-06-13 03:28:26

+0

這真的幫了我很多!謝謝! – ymerdrengene 2014-03-11 15:39:18

1

有不同之處,問題是,一切都剛剛好(當我調試更新變量),但自動完成古怪填充爲

相同的解決方案

當我鍵入sco它有結果但不在列表中顯示 但是當我退格時它顯示sco的結果。在調試中,所有變量都會更新,這隻會告訴我UI未針對AutoCompleteTextView進行更新。因爲當我退格它觸發更新,然後它顯示早期的計算機列表然後它(與此同時它更新它與新的搜索字符串的新列表項) 任何人遇到這個問題?

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 2013-10-18 11:33:29