Whenever I have lists with one TextView only I always wonder whether it is still worth using the ViewHolder pattern?
if(convertView == null){
//convertView = Inflate the view
}
((TextView)convertView).setText(getItem(position).x);
Would I gain any performance on using the ViewHolder here? To me it seems that the whole point of the holder is to cache .findViewById(R.id...) but in this case I dont even need to find any views since the base view is the one im looking for.
Its useful only if you have to call findViewById() every time. In your case you need not search for a View, so, not required.
You are right. The main aim of ViewHolders is to cache results of slow findViewById. It is not needed in your case.
I think it is a good question. If you look at the presentation or Romain Guy
http://www.google.com/events/io/2010/sessions/world-of-listview-android
he shows at 12:38 some speed result showing the performance improvement in the presence of images and by comparing to the use of findViewById.
As you say the goal is to cache the results instead of using findViewById, so it is useless in your case.
Related
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
I have a ListView that I am filling with different views depending on the index. This works fine by overriding the getView method, but I am wondering if this is the best way of accomplishing this? The main reason I ask is when I scroll some of the views seem to get screwed up, such as having the wrong background that I set.
Maybe it would help if someone could explain what convertView is exactly and the correct way of implementing it. Because I am concerned that the reason why my views are getting the wrong background is because I am using the convertView coming in to the function and it is not correct.
When you are recycling views you need to realise that the current convertView (when convertView != null) you are dealing with is already in a certain state (e.g. has a certain background for a different element). Therefore you need to make sure you set every part of the view accordingly and assume no default values.
Think of it this way, when you are scrolling downwards, the top view is moved out of visibility and reused as the new view appearing at the bottom - if you don't change anything for this view, it will look exactly the same as before.
Regarding convertView maybe this part from the Commonsware books might help you(page 107 if you want to jump).
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.
I am building a complex view based on dynamic data. Depending on the number of data elements in collections I am adding more views. Each of these subviews are complex and get inflated in the loop through the data collection.
This is of course inefficient and I would like to figure out a way to inflate the subview only once and then reusing them instead. Is this possible somehow?
PS: I do not want to build up the subviews in code (I know I could) because that would make things even messier due to the complexities and number of subviews, but if the performance would increase considerably I might take a look at that.
PPS: There is no visible performance problem but traceview that most of the time is spent inflating and if I can make it faster I would love to ;-)
you can check out the Google IO Session entitled 'The world of ListView'.
It explains very nicely how to prevent inflating the same view again and again, and how to reuse a particular view if it has been already inflated earlier.
Here is the link.
http://www.google.com/events/io/2010/sessions/world-of-listview-android.html
You can either download the .pdf file or view the video.
Hope it helps.
Regards,
Mahendra Liya.
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?