2011-01-05 26 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

相关问题