I saw that there were many problems regarding notifyDataSetChanged(). I've looked through many of them and none of the solutions worked for me.
I am using ArrayList to set my list, and after my ArrayList is updated, i ran notifyDataSetChanged(). The new list is added onto the previous one.
lets say first list is a,b and new list is a,b,c. what i get in the end is a,b,a,b,c.
and each time updating this happens again with the new list.
I've tried other such as invalidate(), adapter clear(), refreshDrawableState() etc and nothing worked.
Thank you in advance.
Here is the simplified code, a note that changing MainActivity extends Activity to ListActivity crashes the program even after i change the code in .xml file.
public class MainActivity extends Activity
{
ArrayList<String> names = new ArrayList<String>();
ArrayAdapter arrayAdapter = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView lv1 = (ListView) findViewById(R.id.listview);
arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, names);
lv1.setAdapter(arrayAdapter);
}
//code here to edit the ArrayList names.
public void onResume()
{
super.onResume(); // Always call the superclass method first
//the activity need to be updated everytime it resumes.
arrayAdapter.notifyDataSetChanged();
}
}
Seems like you are not properly updating the array list. Please try logging the array list contents after updating.
Related
I have 2 activity.
In activity 1, i have a listview show data from database and button Insert
Activity 2 use to add something to database.
When I click button ADD in activity 2, i call method finish() and return to activity 1.
So, somebody can show me how to reload listview in activity 1 please?
Recreating the adapter should help, because you need to get a new dataset as Kaaaarll said.
So for example you have something like this in your code:
MyData data = database.getData();
MyAdapter adapter = new MyAdapter(data);
ListView list = new ListView();
list.setAdapter(adapter);
and in the next run, in the onResume(), get fresh data and reapply the adapter:
MyData data = database.getData();
MyAdapter adapter = new MyAdapter(data);
list.setAdapter(adapter);
You can re-query the database to get the latest data and then repopulate your listview's adapter.
Notify the dataset in the onResume() method activity 1. It should be something like listViewAdapter.notifyDataSetChanged();. Don't forget to check whether they are null or not.
Let me know if it worked.
EDIT:
Something like this should do the work (in activity 1):
#Override
protected void onResume() {
super.onResume();
if (listViewAdapter != null) {
listViewAdapter.notifyDataSetChanged();
}
}
Here is my scenario:
I have a MainActivity and a CustomListViewActivity. In my MainActivity, I have 1 button and 1 spinner. On click of the button, I pass the selected spinner value to the CustomListViewActivity via Bundle and using Intents.
Now, in my CustomListViewActivity, I have a ListView that uses ArrayAdapter for populating it. I send a ArrayList from MainActivity, say for example
items = [abc]
In my CustomListViewActivity, I receive the same and use it to populate my ListView. The first time I do this, my value gets populated. The second time I do the same, the value existing is now replaced with the new one and the ListView shows one item instead of showing two.
So basically the problem is that the ListView is not updating and not showing both the items. Instead it shows me a single item always.
Here are snippets of my code
MainActivity.java
//code inside button click
..
{
items.add(spinner1.getSelectedItem().toString());
Bundle bundle =new Bundle();
bundle.putStringArrayList("data",items);
Intent i = new Intent(MainActivity.this,MyListViewActivity.class);
i.putExtras(bundle);
startActivity(i);
finish();
}
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
Log.i("App","onSave");
icicle.putStringArrayList("data",items);
}
#Override
protected void onRestoreInstanceState(Bundle icicle2) {
// TODO Auto-generated method stub
super.onRestoreInstanceState(icicle2);
Log.i("App","onRestore");
icicle2.putStringArrayList("data",items);
}
MyListViewActivity.java
private ArrayList<String> myItems;
private static String[] titles;
CustomListViewAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_main);
listView = (ListView) findViewById(R.id.list1);
rowItems = new ArrayList<RowItem>();
adapter = new CustomListViewAdapter(this,R.layout.list_item, rowItems);
listView.setAdapter(adapter);
b=getIntent().getExtras();
if(b!=null)
{
myItems=b.getStringArrayList("data");
titles= new String[myItems.size()];
titles = myItems.toArray(myItems);
}
...
int i=0;
while(i<titles.length) {
item = new RowItem(titles[i]);
//rowItems.add(item);
Log.i("ROW", ""+rowItems.size());
i++;
adapter.add(item);
listView.setAdapter(adapter);
}
adapter.setNotifyOnChange(true);
adapter.notifyDataSetChanged();
}
}
How to make the ListView maintain the current data as well reflect the added data?
Thanks in advance
EDIT : Forgot to mention one more thing. In my MyListViewActivity class I have a button above the ListView that on clicked takes me to my MainActivity so that I can add a new Item again. So when I go back to MainActivity and try and add a new Item , it's the new Item that get displayed rather than showing both the previous and the new one
You need to persist and restore your items list in MainActivity's onSaveInstanceState and onRestoreInstanceState methods.
You also probably don't need to close the MainActivity by calling finish() every time you start the ListView activity but that depends on your application.
Basically, the problem you are having is that items is being recreated with each new instance of MainActivity. Since you finish MainActivity, a new instance is used every time you access that activity (and I assume you thought that items would just keep getting items added to it).
I have a listview that shows the contents of an arraylist. I'm using a simple adaptor to make this possible like so.
public static ArrayList<String> homeScreenContacts = new ArrayList<String>();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.home_screen_contacts_view, NewContact.homeScreenContacts);
The second line is giving me a null pointer exception. I thought about it and I decided it was because the arrayList is empty. So I added the following line between the arraylist declaration and the arrayadaptor declaration...
NewContact.homeScreenContacts.add("A Contact");
This solved the problem and my code worked fine but Now the list view shows "A Contact" and I dont want it to. Is there anyway to get rid of the null pointer exception problem but still have the arraylist empty? Because I want to populate it with user made contacts, not hard-coded, random strings. Thank you.
EDIT: Sorry, The arraylist is located in another class called NewContact, also, I am very beginner Android Programmer I just started.
Simple solution just don't initialize the ListView if there is no element in the ArrayList or the ArrayList is null.
if(NewContact.homeScreenContacts != null && NewContact.homeScreenContacts.size() > 0){
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.home_screen_contacts_view, NewContact.homeScreenContacts);
listView.setAdapter(adapter);
}
Also you need to remember that if you you haven't initialize Adapter then dont initialize the ListView and before any operation on list view you should check is it null or not.
As you have said that you want to populate when user add some contact in the application then on add event only you need to populate or update the ListAdapter.
Hope this solution will resolve your problem.
Try this code
public class YourActivity extends Activity
{
private ListView lv;
public void onCreate(Bundle saveInstanceState) {
setContentView(R.layout.your_layout);
lv = (ListView) findViewById(R.id.your_list_view_id);
// Instanciating an array list (you don't need to do this, you already have yours)
ArrayList<String> your_array_list = new ArrayList<String>();
your_array_list.add("foo");
your_array_list.add("bar");
// This is the array adapter, it takes the context of the activity as a first // parameter, the type of list view as a second parameter and your array as a third parameter
ArrayAdapter<String> arrayAdapter =
new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, your_array_list);
lv.setAdapter(arrayAdapter);
}
}
Works fine for me:
if(arrayList.isEmpty())
{
listView.setAdapter(null);
}
else
{
listAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,arrayList);
listView.setAdapter(listAdapter);
}
I've been playing around with ArrayAdapters and I've reached a point where I'm getting different results from two almost identical ArrayLists + ArrayAdapter combinations.
The first one:
An ArrayList of 'Restaurant' objects, an ArrayAdapter that uses this ArrayList and a ListView that binds this ArrayAdapter.
private ArrayList<Restaurant> model = new ArrayList<Restaurant>();
private ArrayAdapter<Restaurant> restaurantAdapter = null;
...
public void onCreate(Bundle savedInstanceState){
...
restaurantAdapter = ArrayAdapter<Restaurant>(this, android.R.layout.simple_list_item_1, model);
...
listView.setAdapter(restaurantAdapter);
...
}
The second one:
An ArrayList of String objects, an ArrayAdapter that uses this ArrayList and a AutoCompleteTextView that binds this ArrayAdatper.
private ArrayList<String> prevAddressList = new ArrayList<String>();
private ArrayAdapter<String> addListAdapter = null;
...
public void onCreate(Bundle savedInstanceState){
...
addListAdapter = ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, prevAdddressList);
...
autoCompleteField.setAdapter(addListAdapter);
...
}
I have a save button, on click, I'm creating a restaurant object with a name and an address and adding it to the first adapter, additionally, I want to create a list of previously used address so they are "auto completed" next time they are typing it, so I'm taking the text, and adding it to the second adapter.
...onSave = new View.OnClickListener(){
...
restaurantAdapter.add(r); //r is a Restaurant object.
addListAdapter.add(autoCompleteField.getText().toString());
...
}
Now, everything is working properly. I get the Restaurants displayed in a ListView. The AutoComplete is working as expected.... but I noticed something when I was checking the values while debugging:
The actual ArrayLists, model (Restaurant) is getting updated after adding an object to the adapter , but prevAddressList (String) is not.
Unless, I set the AutoCompleteTextField empty.... then, the prevAddressList gets updated after adding something to the second adapter.
Already tried using notifyDataSetChanged(), but it makes no difference (and it is set to true on every adapter by default anyway).
Other behavior that differs between the two adapters is that in the first one (Restaurant), values are going to the mObjects field, while in the second one (String) they are going to mOriginalValues instead.
I'm completely stomped. The only difference between those two adapters is that one is type "Restaurant" and the other is type "String".
Any ideas? Maybe I'm missing something very obvious? Let me know if you need the full code.
thanks
Instead of adding it to the adapter, try adding the object to your list and then calling notifyDataSetChanged on your adapter. The adapter should pick up your changes and your list of course will have the object you just added.
For anyone coming here from google:
Unable to modify ArrayAdapter in ListView: UnsupportedOperationException
This might explain the behavior, although I have to test it myself.
In my activity there is a listview containing lines of a text file. To populate this listview i created an arrayadapter in the onCreate(Bundle savedInstanceState) method. The listview is populated with items if there are lines in the file. The arrayadapter part looks like this:
final ListView lv1 = (ListView) findViewById(R.id.ListView01);
ArrayAdapter<String> adapter1;
adapter1 = new ArrayAdapter<String>(Main.this,R.layout.list_black_text,R.id.list_content, assignArr0);
lv1.setAdapter(adapter1);
adapter1.notifyDataSetChanged();
Then by clicking on Menu item1 (so now we are outside the onCreate(Bundle savedInstanceStat) method i write one line in the text file. For now everything works fine. If i exit and reopen the app the new line appears in the listview. But the listview is not refreshed after adding the new line, so at the end of the " case R.id.Menu1:" part.
So after adding one line to the file I want to refresh the listview by reading the lines from the file to an array then populating the listview with that array. Problem is that i cannot do that, even if i put the ArrayAdapter<String> adapter1; line outside the onCreate() method where the other arrays and variables are declared.
It does not see the listview (lv1 cannot be resolved).
If i define the ListView where the other variables are (ListView lv1;) this whole part of the program is not working.
I also need to empty the listview (the adapter?) by adapter1.clear(); or sg before populating it.
Any ideas are welcome.
If you need those variables to be global, you should declare them as
private final ArrayList<String> assignArr0 = new ArrayList<String>();
private ListView lv1;
private ArrayAdapter<String> adapter1;
#Override
public void onCreate(Bundle icicle)
{
lv1 = (ListView) findViewById(R.id.ListView01);
adapter1 = new ArrayAdapter<String>(Main.this,R.layout.list_black_text,
R.id.list_content, assignArr0);
lv1.setAdapter(adapter1);
}
You should set the adapter to the ListView only one time, inside the onCreate method of your activity, and the notifiyDatasetChanged should be called after you made changes to the list (the array used in your ListAdapter).
Say you have a method to add the recently read lines not yet included in your list. After adding the lines to the ArrayList used in the ListAdapter, you should call the notifyDatasetChanged method, to visualize the new items in the ListView:
private void addLinesToList(final String... newLines)
{
assignArr0.addAll(Arrays.asList(newLines));
adapter1.notifyDataSetChanged();
}
If you are reading the whole file every time it changes, and populate it from top (not just inserting the new lines), you have to first remove all the elements of the list, so the first line of the addLinesToList method should be:
assignArr0.clear();