Android, функция добавления () ArrayAdapter не работает - PullRequest
11 голосов
/ 01 марта 2010

У меня есть ArrayAdapter (myAdapter), присоединенный к компоненту AutoCompleteTextView (textView).
После того, как пользователь нажмет символ, я хотел бы заполнить раскрывающийся список AutoCompleteTextView элементами, содержащими этот символ.
Я получаю элементы, используя AsyncTask (который использует веб-сервис).

Я вызываю myAdapter.add (item), но раскрывающийся список пуст.
Я добавил вызов myAdapter.getCount () после каждого добавления, и он каждый раз показывает ноль. Вызов notifyDataSetChanged () не помог.
Я даже пытался добавить простые объекты String вместо своих пользовательских объектов, но безрезультатно.
Что я делаю неправильно?

Редактировать: Я изменил код, как предложено Miette ниже, но все еще безрезультатно.
Как правило, после изменения текста в моем представлении автоматического завершения текста я вызываю новый AsyncTask и передаю ему введенный текст и обработчик (см. AfterTextChanged ()). Задача извлекает объекты, относящиеся к тексту, и после этого вызывается метод handleMessage () обработчика. В handleMessage () я пытаюсь заполнить объекты адаптера. Но выпадающий список адаптера остается пустым.

Вот мой код:

public class AddStockView extends Activity
        implements OnClickListener, OnItemClickListener, TextWatcher {  

    ArrayAdapter<Stock> adapter;
    AutoCompleteTextView textView;
    Vector<Stock> stocks;
    public AddStockView() {
      // TODO Auto-generated constructor stub
      stocks = new Vector<Stock>();
    }

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      requestWindowFeature(Window.FEATURE_NO_TITLE); 
      setContentView(R.layout.add_stock_view);

      findViewById(R.id.abort_button).setOnClickListener(this);

      adapter = new ArrayAdapter<Stock>(this,
      android.R.layout.simple_dropdown_item_1line, stocks);
      //adapter.setNotifyOnChange(true);
      textView = (AutoCompleteTextView)
      findViewById(R.id.search_edit_text);
      textView.setAdapter(adapter);
      textView.setOnItemClickListener(this);
      textView.addTextChangedListener(this);

    }
    @Override
    public void onClick(View v) {
      // TODO Auto-generated method stub
      switch (v.getId())
      {
        case R.id.abort_button:
        finish();
        break;
        case R.id.search_edit_text:

        break;
      }
    }
    @Override
    public void onItemClick(AdapterView<?> parent, View v,
                            int position, long id) {
      // TODO Auto-generated method stub
      Stock stockToAdd = (Stock)parent.getAdapter().getItem(position);
      //TODO: Add the above stock to user's stocks and close this screen
      finish();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {  
      super.onCreateOptionsMenu(menu);  
      getMenuInflater().inflate(R.layout.menu, menu);  

      CategoryMenu.getInstance().populateMenu(menu);
      return true;  
    }  

    @Override  
    public boolean onOptionsItemSelected(MenuItem item) {  
      CategoryMenu.getInstance().menuItemSelected(item, this);
      return false; 
    }  

    @Override  
    public boolean onPrepareOptionsMenu(Menu menu) { 
      return true;  
    }
    @Override
    public void afterTextChanged(Editable text) {
      // TODO Auto-generated method stub
      if (text.toString().equals(""))
        return;
      new AppTask().execute(new AppTask.Payload(Consts.taskType.SEARCH_STOCK,
                                          new Object[] {text, handler}, this));

    }
    @Override
    public void beforeTextChanged(CharSequence a0, int a1, int a2, int a3) {
      // TODO Auto-generated method stub
    }
    @Override
    public void onTextChanged(CharSequence a0, int a1, int a2, int a3) {
      // TODO Auto-generated method stub
    }
    private void addStockItemsToAdapter(Vector<Object> dataItems)
    {
      for (int i = 0; i <dataItems.size(); i++)
      {
        Stock stk = (Stock)dataItems.elementAt(i);
        stocks.add(stk);
      }
    }

    public void populateAdapter()
    {
      addStockItemsToAdapter(ContentReader.getInstance.getDataItems());    
      adapter.notifyDataSetChanged();
      int size = adapter.getCount(); // size == 0 STILL!!!!
      textView.showDropDown();
    }
    final Handler handler = new Handler() {
      public void handleMessage(Message msg) {
        populateAdapter();
      }
    };
}

Большое спасибо, Роб

Ответы [ 3 ]

12 голосов
/ 08 февраля 2012

У меня была точно такая же проблема. Изучив исходный код ArrayAdapter и AutoCompleteTextView, я обнаружил, что проблема заключается в том, что:

  • исходный список объектов хранится в ArrayAdapter.mObjects.
  • Однако AutoCompleteTextView включает фильтрацию ArrayAdapter, что означает, что новые объекты добавляются в ArrayAdapter.mOriginalValues, тогда как mObjects содержит отфильтрованные объекты.
  • ArrayAdapter.getCount() всегда возвращает размер mObjects.

Мое решение состояло в том, чтобы переопределить ArrayAdapter.getFilter(), чтобы вернуть нефильтрующий фильтр. Таким образом, mOriginalValues равен null, а во всех случаях используется mObjects.

Пример кода:

public class MyAdapter extends ArrayAdapter<String> {
    NoFilter noFilter;
    /*
    ...
    */

    /**
     * Override ArrayAdapter.getFilter() to return our own filtering.
     */
    public Filter getFilter() {
        if (noFilter == null) {
            noFilter = new NoFilter();
        }
        return noFilter;
    }

    /**
     * Class which does not perform any filtering.
     * Filtering is already done by the web service when asking for the list,
     * so there is no need to do any more as well.
     * This way, ArrayAdapter.mOriginalValues is not used when calling e.g.
     * ArrayAdapter.add(), but instead ArrayAdapter.mObjects is updated directly
     * and methods like getCount() return the expected result.
     */
    private class NoFilter extends Filter {
        protected FilterResults performFiltering(CharSequence prefix) {
            return new FilterResults();
        }

        protected void publishResults(CharSequence constraint,
                                      FilterResults results) {
            // Do nothing
        }
    }
}
2 голосов
/ 01 марта 2010

Создайте адаптер массива с вектором или массивом, например:

ArrayAdapter(Context context, int textViewResourceId, T[] objects)

Инициализировав массив arrayapapter, вы заставите его слушать массив объектов. Не добавляйте элемент в адаптер и не очищайте адаптер, делайте свои добавления в массиве «объекты», а также очищайте его. После внесения изменений в этот массив вызовите

adapter.notifyDataSetChanged();

Более конкретно

ArrayAdapter<YourContentType> yourAdapter = new ArrayAdapter<YourContentType> (this,R.id.OneOfYourTextViews,YourDataList);

yourAdapter.notifyDataSetChanged();    
aTextView.setText(yourAdapter.isEmpty() ? "List is empty" : "I have too many objects:)");

Это должно быть сделано после загрузки YourDataList, я проверил ваш код, вы уверены, что обработчик вызывает addStockItemsToAdapter(), прежде чем посмотреть, что ваш адаптер пуст или нет? Вы также должны проверить, есть ли в векторе акции какие-либо элементы.

0 голосов
/ 01 марта 2010

Где вы вызываете addItemsToAdapter ()? Можете ли вы показать нам, как вы пытались добавить простые строки в ваш адаптер?

Редактировать: из комментариев пример полезного кода:

adapter = new ArrayAdapter<Stock>(this, android.R.layout.simple_dropdown_item_1line, stocks);
adapter.notifyDataSetChanged();
textView.setAdapter(adapter);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...