user1841702 user1841702 - 3 months ago 25
Android Question

Android - ArrayAdapter duplicates ListView items

I have a

ListView
widget (positioned below other UI elements) that is part of an
Activity
that does not extend
ListActivity
. I am trying to write a basic feature that adds extra items to the
ListView
upon clicking a
Button
. This data is obtained from an
EditText
. I define the
Adapter
, an
ArrayAdapter
in my case, for the
ListView
in
onCreate()
and set the adapter for the
ListView
using
setListAdapter()
. However when I try to add an extra item to the
ListView
two items are added in the place of one (an item and its duplicate). More detail on this below.

The function that responds to the
Button
click and attempts to add an extra element before calling
notifyDataSetChanged()
is as:

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();
}


When I do not include this line:


b.add(data);


a single item is added to the list which is expected behaviour as
adapter.add(Object)
appends an extra item to the list. However even queerer, is that when I do not include
adapter.add(Object)
a list item is still rendered in the list.


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();
}


After a bit of debugging I found that this is owing to the addition of a data item to the
ArrayList
, i.e.
b.add(data)
where b is an ArrayList of Strings, causes an item to be included in the
ListView
despite not calling adapter.add(Object)`.


Q1. Why is this happening ?

Q2. As an extension, does this mean that the
ArrayList
is 'coupled' to my
ArrayAdapter
(as it was constructed using the ArrayList as a argument) implying that I needn't call adapter methods like add() or clear() to manipulate my
ListView
?

Here is the full code for my Activity as well:

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();
}

}


I also had a look around other SO posts, but they have not given me the answers I was looking for.

ArrayAdapter in android to create simple listview

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

Duplicated entries in ListView

Any direction or an explanation on this would be most appreciated. Also thank you very much for your time.

Answer

It looks like you've already tracked down the answer. By providing the ArrayList to the ArrayAdapter, you have, effectively, coupled the two. In order to update the data, all you need to do is add a new element into the ArrayList.

The .add() method is just a shortcut to this. All it does is add the provided element into the ArrayList. You can add the element either way, just don't do it both ways.

What's the point of notifyDataSetChanged() then? Just because you update the ArrayList doesn't mean that the ListView knows there is new data. Thus, new data might exist, but the view might not refresh itself. Calling notifyDataSetChanged() tells the ListView to look for new data and redraw itself so that the user sees the change.


From the Android documentation for ArrayAdapter.notifyDataSetChanged():

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()