Improving Scroll Smoothness in an Android ListView - android

I have a an Android ListView that has small (say, 1-5 frame) stutters as it is scrolling, about every second or so. I realize that many Android phones have these problems with animation smoothness, however, on my phone (Motorola A855 running Android 2.2), the native contact list scrolls quite smoothly. The item view in the contact list is more complex than the item view in my list, which is:
<RelativeLayout>
<TextView />
<TextView />
</RelativeLayout>
I only want to achieve smoothness as good as the native contact list. It seems like this should be possible without optimizing in native code, but perhaps I'm wrong about that.
I have tried a few things: I simplified the item view even further, and I tried instantiating it programmatically instead of in XML. I also tried changing the way I react to item click events, as per this link:
http://groups.google.com/group/android-developers/browse_thread/thread/7dc261a6b382ea74?pli=1
None of these things seem to have any effect on performance.
Is there anything I can do in my app to improve performance? I'm looking to deploy this app to a number of phones, so changing settings on the phone or rooting the device is not an option in my case. Here is the getView method from my adapter class:
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater flater = (LayoutInflater)context.getSystemService(ListActivity.LAYOUT_INFLATER_SERVICE);
layout = flater.inflate(R.layout.song_view, parent, false);
TextView first = (TextView)layout.findViewById(R.id.firstLine);
TextView second = (TextView)layout.findViewById(R.id.secondLine);
Thing t = array.get(position);
first.setText(t.title);
second.setText(t.name);
return layout;
}
Thanks in advance!

It's difficult to know why this may be happening without seeing your code.
However, one place to look is your getView() method in your ListAdapter (assuming you're using a custom adapter). Try and re-use the View that's passed as an argument to this method rather than creating a new one each time. Also don't do anything too heavy in this method (e.g. a network call), in fact try to make it as lean and mean as possible for best performance.

Did you tried Efficient Adapter
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/List14.html
From my perspective, Problem of animation smoothness is due to garbage collector running in background. If you are creating lots of object then you will see lag in listview scroll.
Hope this help.

Related

Android convertView, to use it or not?

In the article Multithreading For Performance from Android Developer Blog, convertView is used in Adapter.getItem() to display a list of ImageView, which are downloaded through HttpRequest.Yet, I also see some Android tutorials that don't use the convertView, and just inflate a new view in Adapter.getItem().
I'm wondering what's the advantage of using convertView? How does it recycle the used view? Where are the used view cached?
I ask this question because I didn't use convertView in my project and I want to know the cost for not using it. Below is my implementation of a listView of images.
Instead of using convertView, I inflate a new view in Adapter.getItem(). Besides, I create a wrapper class to hold the staff in each item of listView. Once the image is downloaded, it will be stored as bitmap in the wrapper class for each list item(The image is small). In this way, I can avoid the duplicate downloading of the same image. And this also avoid the race condition issues talked in Multithreading For Performance. But I'm still a little worried, is there any issues that not good by using my method?
FYI: the article recommended by #Carl Anderson gives details about how convertView works in adapter. The Google IO by Romain Guy that is suggested in this article is another good reference.
In a word, using convertView is both space and time optimized. Besides, I've abandoned my own imageDownloader and use the Picasso that is recommended by #CommonsWare. It works like a charm.
The problem with not re-using the convertView is that, as you said, you are creating and inflating a new View each and every time the user scrolls a row into view. Creating and inflating a view is a huge amount of time compared to reusing existing views, and you are certainly paying a performance hit for it.
My app does something similar - it uses ImageViews inside of rows in a ListView, and those ImageViews are populated by images that are downloaded in the background. As part of my investigation into a threading bug, I turned off reuse of Views, and the performance was absolutely terrible when I did that. ListView code is optimized for view reuse, and if you don't hold up to that, your framerate and usability will suffer.
Reading this link also helped me understand a lot better how ListViews work:
http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
I also see some Android tutorials that don't use the convertView, and just inflate a new view in Adapter.getItem().
That is not a good sign.
I'm wondering what's the advantage of using convertView?
It saves CPU time and generates less garbage in the heap.
How does it recycle the used view?
It is the used view.
Where are the used view cached?
In AdapterView.
I ask this question because I didn't use convertView in my project and I want to know the cost for not using it.
Well, depending on how you wrote your adapter, you might be getting row recycling "for free" from your superclass.
Below is my implementation of a listView of images.
There is no code in your question.
Instead of using convertView, I inflate a new view in Adapter.getItem().
Only do that if convertView is null. Otherwise, use convertView. This takes one if/else construct.
Once the image is downloaded, it will be stored as bitmap in the wrapper class for each list item(The image is small). In this way, I can avoid the duplicate downloading of the same image.
I do not quite understand where/how you are downloading the image. There are many, many libraries that do this for you, and using one is usually a better idea than is rolling your own code. I like Picasso and Ion for this, but there are others.
But I'm still a little worried, is there any issues that not good by using my method?
There may be more than what I have listed, but without seeing any code, it is difficult to guess what may be not good.
The convertView item is just a helper view, although a very important one, that helps you create less Views.
ConvertView is an optimization that has less to do with image downloading, than with regular view creation. Inflating views in android is an expensive operation, and if your list has many items, and particularly more items that can fit on one screen, the device will have to create several almost identical views to populate your listView.
Instead when you use convertView you help the system create less views, because it gives you the ability to reuse views that the system already created but that are not visible to the user, so you just need to change its contents instead of creating a new view for every item.
Not using convertView is a common cause for lag when scrolling your listviews
Using convertView in the most basic way is simply for recycling views rather than creating new views each time the view is needed, hence if your listview never losses view you might not need to implement it eg a short listview of about 3-4 views. But it is good practice check this google I/o presentation

Should I use SurfaceView or View for a frequently updated view (15fps)

I am building an application where I need to display signal traces in real time (think the kind you see on cardiac monitors in hospitals). For my line animation to appear smoothly I'd like the frame rate to be around 15 frames per second (I did some experimenting to come to the conclusion this was the lowest acceptable frame rate). It probably does not matter in the context of this post but I potentially have numerous such view in a ListView (~20 is common with about 5 being displayed each time).
Until now I've been doing this using a custom view, extending the View class. I have a thread in the containing fragment that calls invalidate() on the view every ~70ms that redraws the view. This is not causing problems per se as I've optimized my onDraw() function to run in under 2ms most of the time.
Now I have added a Spinner to the fragment and while debugging it I noticed that once I opened the Spinner the adapter was constantly hitting getView() calls, even though I was not touching the Spinner (i.e. open but not scrolling) and also lagging a bit. This led me to realize that my whole fragment was being redrawn every ~70ms which to me sounds bad. Now the questions:
Is there a way to trigger onDraw() on a child view without it causing a redraw of the complete hierachy?
Should I just resort to a SurfaceView? (that would not cause a complete view hierarchy redraw, right?)
I've noticed that the SurfaceView is not HW accelerated. Does that matter if I'm only using basic draw functions (drawLine() and drawText())?
Would GLSurfaceView be any better in my case?
I'll try to answer my question so that it might be useful to other people who might encounter the same.
Containing a bunch of SurfaceViews inside a ListView is a fail. It seems to me since the SurfaceView drawing is not synced with the rest of the UI you will get black lines flickering between views when you scroll (which is probably since the SurfaceView is reassigned to new data source via getView() and displayed before it gets a chance to redraw itself). Triggering a redraw inside getView() was not enough, apparently.
Delyan's first comment to my question was valid even though it might not always apply. If I go through each view in the ListView by hand and call invalidate() on it the redraw will not bubble up through the hierarchy (I did not need the invalidate(l,t,r,b) signature, but it's probably a smart idea to try it out if you're having problems with excessive redraws). So, even though Romain Guy mentions in his talk that invalidate() will bubble up to the root it's apparently not always the case. Delyan's comment about different implementation of HW/SW might be the reason - I'm rendering my views in HW.
Anyhow, to work around the issue I created this method inside my adapter:
public void redrawTraces(ListView lv) {
final int viewCount = lv.getChildCount();
for(int i=0; i < viewCount; i++) {
final View stv = lv.getChildAt(i);
if(stv != null) {
stv.invalidate();
}
}
}
Where the views were not SurfaceViews. Finally, to make it clear what I was doing wrong, I was doing this:
adapter.notifyDataSetChanged();
This call did bubble up and caused a redraw through the entire hierarchy. My assumption was that this was roughly the equivalent of calling listView.invalidate() in terms of updating the whole hierarchy; perhaps that's correct I didn't look into it.

How do native Android 4.0 apps have very fast scrolling ListViews?

I am comparing performances, specifically scrolling speeds of a ListView, of apps that I create, to native Android 4.0 apps - Gmail, Gtalk, etc.
One thing I have noticed is that the scrolling frame rate of a ListView on the native Android apps are very high - almost 60fps. In my apps, a ListView don't scroll nearly as fast.
Assuming I'm using ListView incorrectly (which I'm not - I've followed everything stated here: http://www.youtube.com/watch?v=wDBM6wVEO70), I decided to create a dummy ListView that just returns a dozen almost empty LinearLayout views as it's rows (yes I'm using convertView correctly). What's disturbing here is that my almost blank ListView has slower scrolling performance than any of the native apps - Gmail, Gtalk, Contacts, etc.
As a side note, a simple ScrollView has really good scrolling performance, but it is inadvisable to use a ScrollView for large lists.
Clearly, the native apps are doing something (or have access to something) that I don't understand. Unfortunately these native apps aren't open source. Does anyone have any insight as to how these native apps achieve such tremendous performance?
After look at the source code for the native email application, I have found that the list items in a list of messages are single Views, not ViewGroups like LinearLayout. That makes for a very flat View hierarchy which leads to a better frame rate while scrolling the list. I think I remember watching a video of a talk by Romain Guy (one of the lead Android UI engineers) that mentioned that the Gmail team did something similar to increase performance.
To achieve this yourself, you'd have to subclass View and draw everything in the View yourself in the onDraw() method.
Here is the source for a message list item in the current email application.
They do a cool trick where you inflate a view (but don't attach it), get the coordinates of where the items go based on the ViewGroup it is in, and cache the coordinates in a Map so when a view is recycled in a list you don't have to inflate that view again. I might try this in a future project of mine!
I hope this helps!
There are some techniques to make ListView faster: caching and using dissapeared list items as new list items to avoid long operation of creating them. You need to create your own class based on ListView to realize these techniques. Read more here.
I also followed on that video to build my list view. In my app, there are not much items (rows). But I think if we just do as the video said, we are on right way, at least on the theory?

android listview

I'm using a list view in my app and which grows dynamically. Initially list contains same contents for entire list row. Each row in list view displays different contents as app progress. I used same list view foe displaying two type of contents. But the problem is when this happens the scrolling of list view become less smooth. please tell me why this happens.
Thanks in advance.
it is hard to tell what the problem is without looking at the code anyways are you using remote images in that listview? or custom listview you have created using base or arrayadapter? if yes then you will have definately perfomance related issue.
The most likely cause I've seen for this so far, is re-creating your View every time it's requested. You should rather see if the current View on your Handler is not created already. If it's created just update it, don't re-create it. If it's not then bring it from the scratch with new and all that stuff.
Basic Android List tutorials have some lines like (I can't remember exactly):
if(v == null){
v = new MyView(...);
}else{
((MyView)v).updateData();
}
return v;
Pay close attention to it.
Hope this helps.

Recycling views in a listview, worth it?

When overriding the baseadapter on an android listview, you have to implement this method public View getView(int position, View convertView, ViewGroup parent). The convertview is the view that was previously pushed off the list when scrolling, and it's given so that you can reuse that view instead of creating a new view.
My question is, is it really necessary to reuse the view? I can understand reusing it if only a piece of the data is changed. But is the overhead of creating a view really THAT significant? Every tutorial on using listviews I've seen tells you to recycle the view, even on trivially simple views like a textview.
I guess my question is why did google decide to make this the default behavior of the getView method?
A couple of reasons to recycle views:
Object creation is relatively expensive. Every additional object that is created needs to be dealt with by the garbage collection system, and at least temporarily increases your memory footprint
This is more important for more complex views, but inflating and laying out the view objects can be expensive. Most often, you are only making minor changes to the view in getView that won't affect the layout (e.g, setting text) so you might be able to avoid the layout overhead.
Remember that Android is designed to be run in a resource constrained environment.
Finally, its already done for you, and it certianly doesn't hurt anything, so why not use it?
Is it necessary? Only if you like an extra 30-40 fps during flings on a Nexus One. :) (See the slides from http://code.google.com/events/io/2010/sessions/world-of-listview-android.html, slides 13-17)
Why make the device do work that it doesn't need to do by ignoring a significant optimization that's been 95% done for you?

Categories

Resources