问题 Android,ArrayAdapter的add()函数不起作用


我有一个附加到AutoCompleteTextView(textView)组件的ArrayAdapter(myAdapter)。
一旦用户按下一个字符,我想用包含该字符的项目填充AutoCompleteTextView的下拉列表。
我使用AsyncTask(使用Web服务)检索项目。

我调用myAdapter.add(item)但下拉列表为空。
我在每次添加后添加了一个调用myAdapter.getCount(),每次都显示为零。 调用notifyDataSetChanged()没有帮助。
我甚至尝试添加简单的String对象而不是我的自定义对象,但无济于事。
我究竟做错了什么?

编辑: 我改变了代码,因为miette建议如下,但仍无济于事。
通常,我所做的是在我的自动完整文本视图中更改文本后,我调用一个新的AsyncTask并将输入的文本和Handler传递给它(请参阅afterTextChanged())。该任务检索与文本相关的对象,一旦完成Handler的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();
      }
    };
}

非常感谢,Rob


12786
2018-03-01 13:33


起源



答案:


你在哪里调用addItemsToAdapter()? 你能告诉我们,你是如何尝试在你的适配器中添加简单的字符串的吗?

编辑:有用的代码示例中的注释:

adapter = new ArrayAdapter<Stock>(this, android.R.layout.simple_dropdown_item_1line, stocks);
adapter.notifyDataSetChanged();
textView.setAdapter(adapter);

0
2018-03-01 13:51



这就是我所做的:我定义了一个Handler并将它放在我的AsyncTask(称为AppTask)参数中,如下所示:<code> new AppTask()。execute(new AppTask.Payload(Consts.taskType.SEARCH_STOCK,new Object [] {text ,handler},this)); </ code>然后,在我的Handler的handleMessage()中,我调用了addItemsToAdapter。至于Strings,我声明了这个数组:private static final String [] COUNTRIES = new String [] {“Belgium”,“France”,“Italy”,“Germany”,“Spain”};而不是调用:myAdapter.add(tmpItem);我打了电话; myAdapter.add(COUNTRIES [i])甚至是COUNTRIES [0]。谢谢你的帮助! - Rob
有没有办法发布整个代码? - Rob
您可以在某处上传简约的项目zip或编辑上面的问题并在那里添加代码...... - WarrenFaith
谢谢你,我编辑了问题并添加了代码 - Rob
嗯...我最后一次与微调器有这样的问题时,我用新数据重新创建了适配器(在你的情况下是新的库存):adapter = new ArrayAdapter <Stock>(这个,android.R.layout.simple_dropdown_item_1line ,股票); adapter.notifyDataSetChanged(); textView.setAdapter(适配器);那对我有帮助...... - WarrenFaith


答案:


你在哪里调用addItemsToAdapter()? 你能告诉我们,你是如何尝试在你的适配器中添加简单的字符串的吗?

编辑:有用的代码示例中的注释:

adapter = new ArrayAdapter<Stock>(this, android.R.layout.simple_dropdown_item_1line, stocks);
adapter.notifyDataSetChanged();
textView.setAdapter(adapter);

0
2018-03-01 13:51



这就是我所做的:我定义了一个Handler并将它放在我的AsyncTask(称为AppTask)参数中,如下所示:<code> new AppTask()。execute(new AppTask.Payload(Consts.taskType.SEARCH_STOCK,new Object [] {text ,handler},this)); </ code>然后,在我的Handler的handleMessage()中,我调用了addItemsToAdapter。至于Strings,我声明了这个数组:private static final String [] COUNTRIES = new String [] {“Belgium”,“France”,“Italy”,“Germany”,“Spain”};而不是调用:myAdapter.add(tmpItem);我打了电话; myAdapter.add(COUNTRIES [i])甚至是COUNTRIES [0]。谢谢你的帮助! - Rob
有没有办法发布整个代码? - Rob
您可以在某处上传简约的项目zip或编辑上面的问题并在那里添加代码...... - WarrenFaith
谢谢你,我编辑了问题并添加了代码 - Rob
嗯...我最后一次与微调器有这样的问题时,我用新数据重新创建了适配器(在你的情况下是新的库存):adapter = new ArrayAdapter <Stock>(这个,android.R.layout.simple_dropdown_item_1line ,股票); adapter.notifyDataSetChanged(); textView.setAdapter(适配器);那对我有帮助...... - WarrenFaith


我有同样的问题。在检查了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
        }
    }
}

12
2018-02-08 11:16



你太棒了! - Anderson
在其他情况下,过滤是您真正需要的,您可以按照说明使用它 这里 在Webservice示例中。 - vfede


使用向量或数组创建数组适配器,如:

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

通过初始化arrayadapter,您将使其侦听对象数组。不要将项添加到适配器或清除适配器,在“对象”数组中添加项目并清除它。更改此数组后调用

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() 在您看到适配器是否为空之前? 您还应该检查股票矢量是否包含任何元素。


2
2018-03-01 14:09



我按照你的建议做了,但它仍然无效。我有一个Handler,一旦数据结构到达,就会调用handleMessage()。在handleMessage()中,我调用一个函数,该函数通过数据结构进行迭代,并将元素添加到适配器的T []对象,然后调用adapter.notifyDataSetChanged()。毕竟这个adapter.getCount()仍然返回零。这到底是什么意思? - Rob
嗨再次,我正在改变你的答案。我已经测试了你想做什么,它对我有用。 - miette
嗨miette,我很感激你调查这个。你建议和沃伦一样,这确实解决了这个问题。顺便说一句,我意识到调用notifyDataSetChanged()现在是多余的,因为“new ArrayAdapter”语句包含更新的数据源。我想我可以在创建适配器时将我的数据源(YourDataList)清空,沿途添加项目并在完成添加时调用notifyDataSetChanged(),但它似乎不起作用,是吗?无论如何,我的男人很有责任。 - Rob
实际上沿途添加物品一定是有效的。要查看此操作,我可以建议调用YourDataList.clear()并手动对YourDataList进行一些添加,例如,当单击虚拟按钮然后调用notifyDataSetChanged()时,它必须以这种方式工作。 - miette