I've got a ListView in my activity that is initially set to some Adapter. Then, after a certain button is clicked, I simply call listView.setAdapter(new DifferentAdapter(this, foo));
Seems to work just fine at first. The UI is updated and all is well. Then eventually, it crashes and the log shows me this:
E/AndroidRuntime(29724): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2, class android.widget.ListView) with Adapter(class android.widget.HeaderViewListAdapter)]
I'm guessing it's not so simple to simply call setAdapter() whenever you want. Do I need notifyDataSetChanged or something? If it matters, I'm not using a ListActivity.
EDIT
Clarification from below: It's pretty straightforward. I have two inner classes in my Activity, each of which extends BaseAdapter. So I've got two different Adapters and at some point I simply want to switch the ListView to use a different Adapter.
Apparently this works fine:
listView.setVisibility(View.GONE);
listView.setAdapter(new MyAdapter(MyActivity.this, mList));
listView.setVisibility(View.VISIBLE);
Related
I have a ListActivity and use a CursorLoader to load the data which is stored in a ContentProvider. I use a custom class extending CursorAdapter to display the list items. In the LoaderCallbacks onLoadFinished I have the following:
public void onLoadFinished(Loader<Cursor> loader, Cursor newCursor) {
cursorAdapter.swapCursor(newCursor);
}
I have a custom layout for the ListActivity which includes a TextView with android:id="#android:id/empty".
The problem is that when I open the application for the first time calling swapCursordoes not refresh the ListView even though there is data to show in the ContentProvider. When I add a new item to the ListView, the list is refreshed properly. However, if I comment out the TextView, which displays a simple text when no data is available, the application works as expected. The swapCursor call automagically updates the ListView accordingly.
Any thoughts on why this occurs or if there is a proper way to do this since I believe calling notifyDataSetChanged won't do the work as the refreshing fails on a very particular case?
You're having this problem because ListActivity automatically sets the empty view (if available) to your ListView.
I'd suggest you try one of these:
Extend activity and after swapCursor call
listView.setEmptyView(findViewById(android.R.id.empty);
Make the empty view gone: android:visibility="gone" and after swapCursor call
findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
#onCreate call listView.setEmptyView(null) and after swapCursor call
listView.setEmptyView(findViewById(android.R.id.empty);
Not sure about all of them, but one of em will certainly work :)
I am trying to display a list fragment in the middle of my activity. The list fragment adapter is a custom adapter (extended from BaseAdapter) with the typical ViewHolder pattern. It is implemented correctly.
I have the adapter set up with greenrobot Eventbus to receive a new List object from an asynctask which does the query in the background (as not to slow down the UI Main Thread).
The problem is the list fragment doesn't have the results of the database query initially so it defaults to empty (and displays the textview in my xml for the main activity which has the id 'empty').
In the end, my adapter, and listviewfragment don't get instaniated at all because it defaults to empty.
Is there a better method to doing this?
How can I get my listview fragment to wait for the data recieved from the asyncTask?
I am going to just do a fragment with a listview in it, instead of a listview fragment, and I'll see if that will help.
As I understood correctly, you did everything okay so far. What you have to do is to add an "update" method to your adapter, and call this whenever your asynctask finished it's job and got the results for you.
This update method should look something like
public void updateAdapterData(List<String> newList) {
mItems.clear(); // say mItems is the global list you have in the adpater
mItems.addAll(newList);
notifyDataSetChanged(); // This will cause the adpater to re-draw it's rows, so now data should be visible in your list
}
And in your fragment you do somehting like:
adpater.updateAdapterData(newList);
Does this help?
I have a ListFragment whose data is populated by a custom adapter ( a SimpleAdapter in my case). I was experiencing issues with using notifyDataSetChanged() from within my class that extended ListFragment. After a lot of looking around and several (useful) Stack Overflow posts later:
listview not updating with notifydatasetchanged() call
Android ListView not refreshing after notifyDataSetChanged
adapters notifyDataSetChanged does not work
notifyDataSetChanged not working
ListView does not update when calling notifyDataSetChanged from a BaseAdapter
I understand that a loose (and highly un-recommended) workaround would be to re-set your adapter using setListAdapter(). However I am now facing issues with this as well.
The documentation, http://developer.android.com/reference/android/app/ListFragment.html#setListAdapter(android.widget.ListAdapter), mentions that setListAdapter()
Provides the cursor for the list view.
But I still have some questions.
Q1. Does initializing an adapter multiple times using setListAdapter() 'point' to the same adapter instance ?
Q2. What actually happens when a call is made to getListAdapter() and then to notifyDataSetChanged() when an adapter has been set multiple times using setListAdapter() ?
Q3. This question is based on an assumption from Q2- when notifyDataSetChanged() is called when an adapter is set multiple times, which of those adapter instances (this part is the assumption), if they exist' is actually being notified for change ?
I am a beginner with Android and I believe there a quite a few nuances I do not understand.I would be extremely grateful if you could clarify these questions. Also thank you very much for your time.
Q1. Does initializing an adapter multiple times using setListAdapter() 'point' to the
same adapter instance ?
Ans: Initializing the adapter will point only to the last instance that you set using setListAdapter.
Q2. What actually happens when a call is made to getListAdapter() and then to
notifyDataSetChanged() when an adapter has been set multiple times using
setListAdapter() ?
Ans: It doesn't matter how many adapters that you have initialized, only the last instance will be retrieved using the getListAdapter().When you use notifyDataSetChanged() only the last instance wich is retrieved using getListAdapter() will be refreshed i.e. ; the last instance will be reloaded(By calling the getView).
Q3. This question is based on an assumption from Q2- when notifyDataSetChanged() is
called when an adapter is set multiple times, which of those adapter instances (this
part is the assumption), if they exist' is actually being notified for change ?
Ans: The above answer contains the explanation for this.
I have a fragment class extending ListFragment and I'm having trouble populating the list.
I run an asynctask to retreive and parse data from a webservice which is all working ok but now I'm stuck on where I should set the list adapter to populate my list.
I am currently executing my asynctask in the onCreate() method and trying to populate the list in onActivity created which gives a NullPointerException. If i remove the setListAdapter everything runs fine.
According to the android developer docs, a fragment extending ListFragment returns a ListView from onCreateView() by default so I should have access to it.
Where is the correct place to set my list adapter to populate the list?
Thanks for your help.
You are going to want to set the list adapter in the onPostExecute() in the AsyncTask. You can pass a reference to the ListFragment into the constructor for AsyncTask and call setListAdapter() on that reference.
I have an Activity Class with an inner protected class that extends AsyncTask. I am trying to have the AsyncTask load data in background when I click a button and then display a list based on that data.
here is my code for the setListAdapter:
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_row,
R.id.rowtextview, testArr.toArray(test2)));
the problem is that I can't just stick setListAdapter into the AsyncTask class because it needs a context for the outer class, and the only place it can go is inside the onCreate() in the outer Activity class. If its inside the onCreate, it can only be used once and isnt dynamic. I am not sure how I would go about making the list re-load every time I click a button and search for something new.
Your custom inner AsyncTask is not marked as static right? That means that it actually holds reference to the parent class, which is you Activity. So you can use:
setListAdapter(new ArrayAdapter<String>(YourActivity.this, R.layout.list_row,
R.id.rowtextview, testArr.toArray(test2)));
Easy, make the adapter an instance variable and extend it (trivial) to add your custom updateData(newData) method. In this method you update your data AND call notifyDatasetChanged(). And you're done! That way you only need to set the adapter once and just call updateData() when the AsyncTask comes back.