Fetch AutoCompleteTextView suggestions from service in separate thread

。_饼干妹妹 提交于 2019-12-09 06:13:34

问题


For my AutoCompleteTextView I need to fetch the data from a webservice. As it can take a little time I do not want UI thread to be not responsive, so I need somehow to fetch the data in a separate thread. For example, while fetching data from SQLite DB, it is very easy done with CursorAdapter method - runQueryOnBackgroundThread. I was looking around to other adapters like ArrayAdapter, BaseAdapter, but could not find anything similar...

Is there an easy way how to achieve this? I cannot simply use ArrayAdapter directly, as the suggestions list is dynamic - I always fetch the suggestions list depending on user input, so it cannot be pre-fetched and cached for further use...

If someone could give some tips or examples on this topic - would be great!


回答1:


With the approach above, i also had those problems when typing very fast. I guess it´s because the filtering of the results is done asynchronously by the filter class, so there can be problems when modifying the ArrayList of the Adapter in the ui thread while filtering is done.

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

However with following approach everything worked fine.

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



回答2:


EDITED: Added naive way to avoid the dropdown showing when you click a suggestion.

I do something like this in my app:

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



回答3:


had the same solution except that the problem is that everything is just fine ( variables are updated when i debug) but the autocomplete fills weirdly as in

when i type sco it has the results but does not show in list but when i backspace it shows the result for sco. In debug all the variables are updated which only tells me that the UI is not getting updated for AutoCompleteTextView. as when i backspace it is triggered for update and then it shows earlier computer list then it(in the mean time it updates it with the new list items for new search string. anyone ran into this problem?



来源:https://stackoverflow.com/questions/4609043/fetch-autocompletetextview-suggestions-from-service-in-separate-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!