Получить предложения AutoCompleteTextView из службы в отдельном потоке - PullRequest
6 голосов
/ 05 января 2011

Для моего AutoCompleteTextView мне нужно получить данные из веб-сервиса. Поскольку это может занять некоторое время, я не хочу, чтобы поток пользовательского интерфейса не реагировал, поэтому мне нужно каким-то образом получать данные в отдельном потоке. Например, при извлечении данных из БД SQLite это очень легко сделать с помощью метода CursorAdapter - runQueryOnBackgroundThread. Я искал другие адаптеры, такие как ArrayAdapter, BaseAdapter, но не смог найти ничего похожего ...

Есть ли простой способ, как этого добиться? Я не могу просто использовать ArrayAdapter напрямую, поскольку список предложений является динамическим - я всегда выбираю список предложений в зависимости от пользовательского ввода, поэтому его нельзя предварительно выбрать и кэшировать для дальнейшего использования ...

Если бы кто-то мог дать несколько советов или примеров на эту тему - было бы здорово!

Ответы [ 3 ]

10 голосов
/ 01 ноября 2011

При описанном выше подходе у меня также были проблемы при наборе текста очень быстро. Я полагаю, это потому, что фильтрация результатов выполняется асинхронно классом фильтра, поэтому могут возникнуть проблемы при изменении 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;
  }
}
9 голосов
/ 20 января 2011

РЕДАКТИРОВАНИЕ: Добавлен наивный способ избежать раскрывающегося списка при нажатии на предложение.

Я делаю что-то подобное в моем приложении:

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);
    }
}
1 голос
/ 28 сентября 2011
У

было то же решение, за исключением того, что проблема в том, что все в порядке (переменные обновляются при отладке), но автозаполнение заполняется странным образом, как в

, когда я набираю sco, результаты есть, но не отображаютсяв списке, но когда я возвращаюсь, это показывает результат для sco.При отладке все переменные обновляются, что говорит только о том, что пользовательский интерфейс не обновляется для AutoCompleteTextView.например, когда я возвращаюсь, он запускается для обновления, а затем показывает более ранний список компьютеров, затем он (в то же время он обновляет его новыми элементами списка для новой строки поиска. Кто-нибудь сталкивался с этой проблемой?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...