Android - ArrayAdapter 重复 ListView 项目

Posted

技术标签:

【中文标题】Android - ArrayAdapter 重复 ListView 项目【英文标题】:Android - ArrayAdapter duplicates ListView items 【发布时间】:2014-08-20 13:56:48 【问题描述】:

我有一个 ListView 小部件(位于其他 UI 元素下方),它是不扩展 ListActivityActivity 的一部分。我正在尝试编写一个基本功能,在单击Button 时向ListView 添加额外的项目。此数据来自EditText。我为onCreate() 中的ListView 定义Adapter,在我的情况下为ArrayAdapter,并使用setListAdapter()ListView 设置适配器。但是,当我尝试向ListView 添加一个额外的项目时,会添加两个项目来代替一个(一个项目及其副本)。下面有更多详细信息。

响应Button点击并在调用notifyDataSetChanged()之前尝试添加额外元素的函数如下:

public void saveButton(View view)

     EditText editText = (EditText) findViewById(R.id.edit_text);
     String data = editText.getText().toString();
     // duplication caused by this line
        b.add(data);
     ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();
     adapter.add((String)data);
     adapter.notifyDataSetChanged();

当我不包括这一行时:

b.add(数据);

将单个项目添加到列表中,这是预期的行为,因为adapter.add(Object) 将额外的项目附加到列表中。然而更奇怪的是,当我不包含 adapter.add(Object) 时,列表中仍会呈现一个列表项。

 public void saveButton(View view)

     EditText editText = (EditText) findViewById(R.id.edit_text);
     String data = editText.getText().toString();
     b.add(data);
     ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();
     // not calling adapter.add() still includes an item in the list.
     // adapter.add((String)data);
     adapter.notifyDataSetChanged();

经过一番调试我发现这是由于在ArrayList中添加了一个数据项,即b.add(data),其中b是字符串的ArrayList,导致一个项目包含在ListView 尽管没有调用 adapter.add(Object)`。

第一季度。为什么会这样?

第二季度。作为扩展,这是否意味着ArrayList 与我的ArrayAdapter“耦合”(因为它是使用 ArrayList 作为参数构造的),这意味着我不需要调用像 add() 或 clear() 这样的适配器方法操纵我的ListView

这也是我的 Activity 的完整代码:

public class MainActivity extends Activity 

ListView listView;
ArrayList<String> b = new ArrayList<String>();

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    b.add("Liquorice");
    b.add("Dairy Milk");
    b.add("Rice Crispies");
    b.add("Orange-Mint");
    b.add("After-Tens");


    listView = (ListView) findViewById(R.id.list_view);
    ArrayAdapter adapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.layout_file,b);
    listView.setAdapter(adapter);



@Override
public boolean onCreateOptionsMenu(Menu menu) 
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;


public void saveButton(View view)

     EditText editText = (EditText) findViewById(R.id.edit_text);
     String data = editText.getText().toString();
     b.add(data);
     ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();
     adapter.add((String)data);
     adapter.notifyDataSetChanged();



我还浏览了其他 SO 帖子,但他们没有给我想要的答案。

ArrayAdapter in android to create simple listview

Why can't one add/remove items from an ArrayAdapter?

Duplicated entries in ListView

对此的任何方向或解释将不胜感激。也非常感谢您抽出宝贵的时间。

【问题讨论】:

代码中的“b”是什么? b 是一个字符串数组列表,其中包含我要在屏幕上呈现的数据。这也包含在问题中。 从您的代码中删除这两行 ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();适配器.add((String)data);. 【参考方案1】:

您似乎已经找到了答案。通过将ArrayList 提供给ArrayAdapter,您可以有效地将两者结合起来。为了更新数据,您只需在ArrayList 中添加一个新元素。

.add() 方法只是一个捷径。它所做的只是将提供的元素添加到ArrayList。您可以通过任何一种方式添加元素,但不要同时使用两种方式。

那么notifyDataSetChanged() 有什么意义呢?仅仅因为您更新了ArrayList 并不意味着ListView 知道有新数据。因此,可能存在新数据,但视图可能不会自行刷新。调用notifyDataSetChanged() 告诉ListView 寻找新数据并重绘自身,以便用户看到更改。


来自ArrayAdapter.notifyDataSetChanged() 的 Android 文档:

Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.

http://developer.android.com/reference/android/widget/ArrayAdapter.html#notifyDataSetChanged()

【讨论】:

非常感谢您。我还意识到,如果与适配器的数据绑定超出范围,或者如果没有立即访问该数据的方法,比如从另一个类,那么 ArrayAdapter 的 add()、addAll() 或 clear() 方法就是要使用的方法操作该数据源。此外,ArrayList 和 ArrayAdapter 的方法名称和签名完全相同,为您的答案提供了更多的权重。【参考方案2】:

在您的适配器上,验证视图是否为空,如果是,则从您的布局中分配正确的视图,在 if 之后设置值。

@Override
public View getView(int position, View convertView, ViewGroup parent) 
     ViewHolder viewHolder;
     if (convertView == null) 
         viewHolder = new ViewHolder();
         LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         convertView = vi.inflate(R.layout.customswipelayout, parent, false);
         viewHolder.name = (TextView) convertView.findViewById(R.id.rowTextView1);
         viewHolder.price = (TextView) convertView.findViewById(R.id.rowTextView2);
         viewHolder.stockCount = (TextView) convertView.findViewById(R.id.rowTextView3);
         convertView.setTag(viewHolder);
         mItemManger.bindView(view, position);
     

     /* rest of your adapter code */

这是我的一个例子,在我关闭 if 语句后,我分配我的值并返回视图:

viewHolder = (ViewHolder) view.getTag();
final Object object = this.list.get(position);
ImageView cmdDelete = (ImageView) view.findViewById(R.id.cmdDelete);
cmdDelete.setOnClickListener
//more personal code follows

return view;

现在我滚动浏览我的列表,它运行良好!

【讨论】:

以上是关于Android - ArrayAdapter 重复 ListView 项目的主要内容,如果未能解决你的问题,请参考以下文章

UnsupportedOperationException with ArrayAdapter.remove [重复]

android笔记:ListView及ArrayAdapter

Android之ArrayAdapter使用

android中的ArrayAdapter创建简单的listview

android在使用ArrayAdapter时如何分配textViewResourceId

Android_适配器(adapter)之ArrayAdapter