I have a ListView with custom Adapter. To be honest, I have many of them at the same time on screen, and my Tegra 3 device started to lag, what made me really confused... I found than in each ListView's Adapter the getView() method is called for all visible rows every time any animations runs on screen. That gives me like few hundreds of calls per second! Digging more, most of these calls are due to measure() and onMeasure() calls of ListViews' parents, and - this is tke key - they are useless, because all the layouts of my ListViews
have const size.
So my question is: how to eliminate these calls? Of course I want to leave proper calls alone (caused by adding items to Adapter and notifyDataSetChanged() ).
I've tried almost anything, but either the whole list doesn't draw itself (when I overriden it's onMeasure() and forced to returned const size without calling super.onMeasure()) or stops updating at some time.
How you implemented the getView() method? If you implement it in the correct way there should be nearly no lagging.
Check out this really really good video:
http://www.youtube.com/watch?v=wDBM6wVEO70
Slides: http://dl.google.com/googleio/2010/android-world-of-listview-android.pdf
As Romain said, work with it not against it. Best is to leave measure() alone and focus on your adapter.
Thats how ListView is implemented.. I don't think that will cause a performance Overhead.. Provided you do things properly there..
For example..
Don't instanciate LayoutInflator inside GetView Method, Do it at class level..
And Inflate View Only if the convertView==null or else just return convertView.. Inflating view is a costly process....
Well like you said these calls are due to measure() and onMeasure() calls of ListViews parents and I'm sure you are using height=wrap_content also with wrap_content on height your ListView will check without stop if your height has changed.
So the solution is to put the height=fill_parent.
I hope this helped you.
The underlying reason for this is that ListView.onMeasure() calls AbsListView.obtainView(), which will request a view from your list adapter. So if your view is being remeasured through animations, your performance will be very poor.
Related
Performance wise, is it the same to place an onclick listener in a getView() call of an adapter or place the onclick listener outside on a listview that contains the adapter?
My underlying thought is to reduce code if I use the same adapter in two different places. But I need to make sure the performance wouldn't be affected!
The performance difference would be so negligible, I wouldn't even worry about it. Instead opting for whatever seems to be fit for your design approach. If you want to reduce code duplication, putting it in the getView() works just fine.
I'm having some difficult time figuring out when the ListView decides to recycle all it's views. I have 2 different ListViews where i change some layout stuff and play an animation after that. In my first ListView this works fine, only the row i'm trying to change is actually being affected, yet in my other ListView all rows are affected and the Views are being reused.
I can't really post any code, as there are quite a few classes involved in this. I tried to break it down and noticed it reuses the rows after calling requestLayout() at one of the descendant views of the row. But in my other ListView i do the same and it's not called at all.
Nowhere in my code notifiyDatasetChanged() is called either, nor am i changing any other views.
I just trying to find out when ListView actually needs to reuse the views.
ps. I'm using 2.3.3. And i'm aware of setHasTransientState() in 4.1. But i can't use that unfortunately
I found my specific problem.
After long debugging through the source of the ListView I found the difference in behavior between my two ListView implementations. I found out that one of them was calling onSizeChanged(), first to a new height immediately followed by another onSizeChanged() with the old height. In this method it sets a flag mDataChanged which in turn will cause the views to be recycled.
In my other ListView i have fixed row heights so it never has this problem. I'm going to do the same for this situation as i don't really need different row heights.
I am trying to implement an infinite Carousel using the ViewPager component. I based on the one created by Antonyt but there is a problem using less than 4 views. As the view is already in place. Must be a way to trick the Viewpager to draw the same view/page in different places.
I ran into the same problem, couldn't find the solution myself. But i guess it is impossible to do by using only 1-4 views. What the problem is that all the views (for 1-4 images in repetition) will be instantiated at once(or atleast in a very short interval) this interferes with the image loading process because the prev load hasn't finished, so the prev one returns a damaged view. You may handle this something like this though.
1) right after instantiation, use handler with delay of 100-200ms to flip through views setCurrentItem() again and again(around 10 times) in either direction, this way the original 4 will be out of range(if you have off screen page limit, which i hope you have beacause of infinte nature of your code) and will be created one by one later on.
2) Use multiple buffer objects,
1 image-8 buffers
2 images-4 buffers for each
3 images-2 buffers for each... something like this.
neither is an ideal solution but both worked for me but. I would like to know what you tried too.
The solution is to use the same child view in the ViewPager. And to do that without having the same child already assign to a parent is to use a ProxyView with the real view inside. Extends that Fake View from ViewGroup and override the Draw method will do the trick!
You may need to do some works in OnDestoryItem method to re-attach item which have been detached.
I have already post my solution here,https://github.com/antonyt/InfiniteViewPager/issues/2
Try the following trick which I've used successfully to make a (faux)infinite ListView.
In your adapter's getCount() method, return Integer.MAX_VALUE.
Then in the adapter's instantiateItem() or destroyItem(), Use position % datasource.size()
This trick was taken from HERE.
I have a ListView that I am calling smoothScrollBy() on. 95% of the time, the smoothScrollTo() behaves as intended. However there are times that it does not end up in the intended spot! I have verified that I am giving it the same value. I notice that the smooth scrolling is not so smooth when the errors are made, however there are no other tasks that my application is performing that I would have control over.
I am not quite sure what is going on in the background but a likely culprit is garbage collection.
95% accuracy is not good enough in this situation. I am going to have to implement some sort of a correction mechanism to make sure the ListView lands on the correct spot in these instances.
Is there a better way to use smoothScrollBy() other than simply calling view.smoothScrollBy(distance, time);?
sometimes it will be because of the timing issue. When the views are added to your listview and the time you do
view.smoothScrollBy(distance, time);
the listview or the ui still need not get refreshed. So do this in the views post thread with a specific delay. Eg.
view.postDelayed(new Runnable{
view.smoothScrollBy(distance, time);
},1000);
Try some of these:
Listview has its own scrolling mechanism. It scrolls when the content is added.
Assign listview height (android:layout_height) to match_parent or fill_parent.
If your assigning a adapter in a working thread. Do not perform any UI actions in the thread.
If these do not solve the issue. Please post the code where you assign the adapter to the list view if any. Or the relevant code.
Also the xml layout code.
Hope this helps.
When I check my logs, when using ListView, I see, that getView() method of a custom adapter is continuously invoked on first 6 elements, even if I scroll to the very end of the list. Has anyone seen behaviour like this?
Well, the answer has been accidentally found here.
Just never, ever set ListView's dimensions to be "wrap_content".