SimpleAdapter - Adding New Data to List But on Which Thread? - android

I'm using a SimpleAdapter to populate a ListActivity. From the Google I/O video 'the world of ListView' it's made clear that the notifyDataSetChanged() method (for SimpleAdapter) MUST be called from the UI thread. But as regards updating the ArrayList in my ListActivity can that be safely done from any other thread?
Currently I do use a non-ui thread to update data in my ArrayList and then call notifyDataSetChanged() from the UI thread. This works fine and I can also dynamically update the SimpleAdapter too. However there is a certain aspect of my app that can cause it to crash and it happens when my ListActivity is in focus. I'm just currently exploring possible causes of the exception and it was something mentioned in the Google I/O video that left me unsure as to whether I can safely update my ArrayList from another thread.

According to the source code, adapted does not do any kind of synchronization on the underlying data list, so I assume it should only be changed from the UI thread.

Related

App slows down when more than 20 fragments are added to backstack

I have a fragment that loads tabs dynamically into the view pager where data in each tab will be loaded on the result of an api call. Each fragment will have a minimum of 4 tabs. When this fragment is added into the backstack multiple times (normally more than 20), the app starts to lag and it becomes very slow to scroll through the list. Is there a way to solve this?
This issue is related to managing UI Thread & Worker Thread.
Perhaps you are doing so much work in UI Thread. Like filtering list or creating Map (It can be anything, as I cant see your code.) etc.
Solution:
You should do only UI work in UI or Main thread. Like if you are fetching & parsing response.
Fetch api data in Worker Thread (AsyncTask() or new Handler()).
Parse data in worker thread, because parsing too much data will cause UI lagging.
Filter lists or prepare data in same worker thread.
Then use runOnUiThread(); to set your data in List or to set view components.
If you have long list in every fragment then use Pagination.
There can be many other improvements in your code. You should identify and resolve that.
Keypoint is use UI/Main thread for communicating to View. And use Worker Thread for background process.
If you properly manage threads in your app, your app will never hang.

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.

Modify adapter in a background thread

I know that in normal situation, one cannot call ListAdapter.notifyDataSetChanged() in a background thread to update a listview. So I tried to work around like this:
class mythread extends thread {
private ListAdapter listAdapter;
...
public void run() {
listAdpater.setNotifyOnChange(false);
listAdapter.addAll(A_LARGE_ARRAY);
}
...
}
When the thread finishes, it sends a message to a handler running in the UI thread, which would call listAdapter.notifyDataSetChanged() to update the listview.
It seemed to work, except when I tried to debug it, the debugger complained something like "The adapter is changed, while the listview doesn't receive a notification. Make sure that you modify adpater in UI thread only."
Does the android framework monitor the modification of an adapter even I called setNotifyOnChange(false)? Is there any way to work around?
PS. In my own benchmark, by moving listAdapter.addAll(A_LARGE_ARRAY) to a background thread, it saved me about 126ms of execution time, which means, if I modify the adapter in UI thread, it will be blocked for 126ms.
UPDATE
Anyone who run into this problem, please refer to this Google I/O Lecture link. It's really helpful.
You probably wouldn't want to do things this way, your app may inexplicably broke on some device or some version of Android while working perfectly on others.
Remember listAdpater is accessed every time the relating UI is being updated, which runs on the UI thread.
At the same time you are updating the same listAdpater in another thread. This means that:
If the UI is updated while you are modifying listAdapter, the UI may display incorrect items for even throw Exception (depending on the race condition and )
What's being updated to listAdapter in the other thread may not be updated to the main thread, if the OS sees it suitable to run that other thread on another processor, since there's no memory barrier (synchronization), there's no guarantee that these two threads will see the same thing
So the best course of action for you would be still run the changes on UI thread, but only update a fraction of A_LARGE_ARRAY to listAdapter at a time.

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.

Android ListAdapter Repaint

i have the following problem. I fill a ListView with a custom ArrayAdapter with data from a BD. However, in background, i'm updating those datas from the info provided by an API, so the idea is when the update finish, the adapter shows the updated data instead its "old version".
The problem is that when i do that, i notice a lag while the adapter is updating itself. Is the any efficient solution to avoid this?
Thanks
You can call notifyDataSetChanged() on your ListAdapter to cause it to update to the current data immediately. Note that you should do this from the main UI thread, using a Handler or Activity.runOnUIThread()

Categories

Resources