notifyDataSetChanged() blocks UI - android

After I've downloaded a list of objects from a rest service, obviously in an AsyncTask, I set them into a custom BaseAdapter. When I call again the service to load more data and add them to the List of object, and call the notifyDataSetChanged() the ListView block for a sec or two.
I've tried to move the add and notify into another AsyncTask but since I'm modifying the UI this raised an exception.
I've tried also to change the addAll with a loop where I add an item at time and call the notifyDataSetChanged() everytime but with no success.
Which is the best practice in this case?
Sorry for no code but I'm from my phone, this thing really puzzles me.

How many times you are call notifyDataSetChanged()? You need to call it once, after you add all data. If you show code of your AsyncTask class and how do you use it, I will tell more.

Related

Multiple AsyncTask request handling

In one of my project I need to call asyncTask in my getView method of custom adapter.
So ther is multiple asynctask request are in queue.
By default the asynctask work as first in first out.That is first request will process first then it will goes to next one. What i need is last in first out.
How can I handle asyncTask to work as mentioned above?
Also like to whether there is any method to get the count of pending asyncTask request.Searched a lot couldnt find a solution.

Timing of ListView Layout Pass (how to keep a layout pass from running while changing the dataset?)

An answer to another question raised a different question for me.
When displaying a ListView you update the Data Set then call the adapter's notifyDataSetChanged(). This calls requestLayout() and the Google documentation says "This will schedule a layout pass of the view tree"
So apparently we don't really know when that will take place. But during the layout pass many of the custom overrides in the adapter such as getView() and getCount() will be accessing the data set. So if the layout pass is run at an unknown time how do you know when it's safe to alter the data set?
I have a complex data set with multiple arrays that I need to keep synchronized with each other so I make my changes and call notifyDataSetChanged(). After that I may need to make more changes (say, because new data has come in over the network) so how do I make sure a layout pass from the previous notifyDataSetChanged() isn't going to run in the middle of making the new changes?
Also, what does Google mean by "schedule" a layout pass? When I log stuff in getView() the TID shown in the Logcat screen is the same as the main UI thread. so after calling notifyDataSetChanged() if I check for new data and start updating my arrays how does Android manage to run the layout pass in that same thread?
So if the layout pass is run at an unknown time how do you know when
it's safe to alter the data set?
It's very simple: by only updating the data set in the UI thread, you're guaranteed to avoid any problems. Since the layout also occurs in the UI thread, both operations will, by necessity, execute serially. This can be achieved via AsyncTask, Handler, or any other method of thread communication.
Also, what does Google mean by "schedule" a layout pass?
A message is posted for the UI thread's Looper. It will be processed whenever said thread is idle.

How do I get adapter to update views after data changes when using fragments?

I have a list of orders in one fragment. In a second fragment, I display the detail of the order, and I use a third fragment to display the buttons that change the status of the order.
In the list, each order is displayed with a background color that indicates its status, for example green for a completed delivery.
When in landscape mode, both the detail and list are shown. In portrait mode I use two separate activities.
This all works fine, up until I change the status of an order. I can't find a way to get the list to update.
As I understand it, what needs to happen is the adapter needs to have its notifyDateChanged() method called. I've tried calling it directly from the method that processes the button click, I've tried an asynctask, and I've tried a handler. My debug methods show that the call is happening, but the list doesn't get updated.
It's possible I'm doing something completely bone-headed, but I've double and triple checked things. I suspect there is some key element I don't understand. I hope someone else does and will tell me what I'm missing.
I had some code posted, but it was clearly wrong. Not sure what code to post, since I think this is more a conceptual than coding issue.
If you want to update a view, try to use :
Thread + Handler
AsyncTask
What I discovered, through the helpful comments of other posters, is that my problem wasn't that the adapter wasn't getting the notifyDataChanged() call on the correct thread. I put in debug code that proved that. The problem was that the background of the listview item was based on a change in the underlying data itself, so the real answer was to get the Adapter to refresh the Cursor. I made some changes. I modified the AsyncTask I was using to notify the adapter. Now the AsyncTask gets a new cursor and calls adapter.changeCursor(cursor) with the result. The AsyncTask is called from the MainActivity (which hosts both the list and detail fragments) when the status is changed. It's also called in the onResume() portion of the ListFragment code, so the list will be updated properly when coming back from the detail fragment. Works great.

Android how to update a listview periodically

I have an array adapter which is used in my listview. The adapter is periodically updated by fetching or removing contents from a server. I have used a scheduledthreadpoolexecutor to periodically update the adapter and then use adapter.notifydatasetchange();
The list view gets refreshed and removes any items etc, but for example if two items where removed from the list when I scroll the listview on android and get close to the end of the listview the application crashes. I guess something does not get updated in the listview and it things that the size of the list is the initial size.
Do you have something to recommend?
Regards,
Aris
Hi all,
I actually found a solution to my problem and forgot to check here for any replies.
Thank you all for your suggestions.
Basically scheduledthreadpoolexecutor called a runnable (lets call it updateRunnable) to do the updates.
What I did was the following:
In the updateRunnable, when it gets the new data and stores them in the array adapter, it then calls another runnable (lets call it updateListView) using runOnUiThread and in updateListView I set the adapter of the listview.
This solved my problem
If your data is at all database-like, which I assume, given your use of a ListView, then you'll want to refactor your background service into a model that uses a ContentProvider and SyncAdapter to stay in sync with the server, and then automatically notify the ListView through binding it with a CursorAdapter which uses its implementation of ContentObserver to automatically update the list when the underlying DB changes.
Why does ContentResolver.requestSync not trigger a sync? tells you how to set up the ContentProvider.
How to handle REST calls, data persistence, syncing and observing ContentProvider tells you a little more about how list update notification operates once the ContentProvider is syncing.
It's a lot of infrastructure work to get set up, but once you do, there's so much that's wonderfully automatic about the SyncAdapter model.
I had a similar problem once. Since the ListView keeps updating you can
1) display the Listview just as the activity starts in OnCreate, and
2) call this SAME activity so as to display refreshed data in the listview.
but after calling the same activity again, finish() the current instance first immediately since you can get multiple instances of it one over the other.

I am looking to refresh a ListView without reloading the page

I am looking to refresh a ListView without reloading the page. More precisely I have a service that is sending data for a ListView in an Activity, however the Activity loads long before the Service can get the data. So I need to be able to load/reload the ListView after the Activity has already loaded.
I found that notifyDataSetChanged only works if you use the add, insert, remove, and clear functions on the Adapter, so I ended up doing it the following way in a similar implementation:
An AsyncTask fetches all the data in doInBackground. Then, when finished I set the list adapter for the first time in onPostExecute. To let the user know that something is loading, I just put a TextView on top of the Listview and set its text to "Loading.." in onPreExecute and then make it invisible in onPostExecute when the data is ready.
If you need to refresh the data, you just execute the AsyncTask again.
I like this way because you are only setting the ArrayAdapter once (i.e. when you finally have all the data). Here is more on AsyncTask in case you need it. The docs have some nice example code.
Call notifyDataSetChanged() on the ListView's Adapter whenever you want to refresh it.
I would say to use IntentService instead of Service. By, using IntentService you will be able to send data to the background Service and also receive the updated data while firing a BroadCastReceiver to update your UI. Here is a complete example how you can achieve your task using an IntentService.

Categories

Resources