Fetch AutoCompleteTextView suggestions from service in separate thread

后端 未结 3 2175
醉话见心
醉话见心 2021-02-09 16:57

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

相关标签:
3条回答
  • 2021-02-09 17:22

    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?

    0 讨论(0)
  • 2021-02-09 17:40

    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;
      }
    }
    
    0 讨论(0)
  • 2021-02-09 17:45

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题