I have a background thread loading data which I want to display in an Android ListView. The data changes very often (i.e. 1-2 times per second). Sometimes the number of rows in the dataset changes too (but certainly not as often as the data in the cells changes).
There are two ways to update the data in the cells, as far as I can tell:
Have the background thread notify the UI thread that new data is ready, and the UI thread can then call BaseAdapter.notifyDataSetChanged(). However, I have read in more than one place that if that method is called often, it will be slow, because the ListView has to restructure all of its subviews Views.
If the dataset count has not changed, I could possibly find all of the visible ListView cells that are associated with the changed data, and update the values manually without calling notifyDataSetChanged(). This would probably work, but I think its unfortunate that I have to update the views manually when the List Adapter is supposed to handle the update notifications and mechanisms for me when I notify it. This method also won't work if the dataset count changes over time (i.e. not only is the data within each cell of the ListView changing, but the total number of cells in the ListView can grow or shrink based on the background thread supplying realtime data).
I would certainly appreciate thoughts from others who have implemented this scenario, and how they optimized code simplicity and most importantly, performance.
I faced a very similar situation where I stored the textviews of List View in a Hashmap where each textview had a tag to have it identified. When the streaming data arrived, all I did was post a runnable on the textview after finding the correct one and got them updated in no time. However, though the updates were instantaneous the UI faced a drag and went sluggish as I was updating about 30 textviews per second. I had my Listview in a fragment inside a ViewPager and it seemed the UI thread was all clogged up and blocked when streaming was on. Hence, I strongly advise against manual updating of the Textviews in a Listview as far as User experience and performance of the UI thread is concerned
Maybe you can set a Handler on the UI thread. You need to create a class which implements Runnable. Pass an ArrayList to this class. In the run() method create the adaptor with the ArrayList as a parameter, then do a setAapter on the ListView. That's it. You're done. To launch your handler : just to this from your worker thread : handler.Post(new MyUpdateToUI() ); That's it. I hope it is efficient enough for you?
I once implemented a filter like the code beolow using
notifyDataSetChanged()
and had no problems with it.I've also modified the views of a List on the go manually. Both have worked well. In some case I prefear to modify the data manually because its faster and because itdoesn't affect the whole list.
Anyway, views are created on the go when they need to apear on the screen and are deleted when they leave the screen, so if you modify the data used to create the views, if the user scrolls the ListView and the views get out of the screen, in theory, the views will be created with the new data once they come again into the screen.
I would recommend you to try the code below to understand how does
notifyDataSetChanged()
work and decide if it works for you.xml
Hope this helps.
I experimented with
ListView
, and you essentially have to update theListView
cells manually without callingnotifyDataSetChanged()
if you have realtime data and you want theListView
to update with better performance.notifyDataSetChanged()
causes theListView
to rebuild its entireView
hierarchy is very slow if you are calling it frequently (i.e. once every second).Note (2014). This DOES NOT APPLY if you are using normal modern ListView with a ViewHolder pattern. You simply call 'notifyDataSetChanged' and that's all there is to it. It is incredibly efficient as Android knows to only update the cells on the screen.
I implemented a scheme where if my data set size changed from one update to the next, I call
notifyDataSetChanged()
. If the data set size remained constant from one update to the next (such that the number of cells in theListView
is the same as before when a redraw of the data is needed), then I iterate over theListView.getFirstVisiblePosition()
:getLastVisiblePosition()
, and update the visible cells only.