6

对于我来说AutoCompleteTextView,我需要从网络服务中获取数据。由于这可能需要一点时间,我不希望 UI 线程没有响应,所以我需要以某种方式在单独的线程中获取数据。CursorAdapter例如,在从 SQLite DB 获取数据时,使用方法 -很容易完成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 的结果。在调试中,所有变量都会更新,这只会告诉我 UI 没有针对 AutoCompleteTextView 进行更新。当我退格时,它会触发更新,然后它会显示较早的计算机列表(同时它会使用新搜索字符串的新列表项对其进行更新。有人遇到过这个问题吗?

于 2011-09-28T15:59:42.953 回答