Android ListView element invalidate() does not redraw - android

In my Android App, I have a ListView which contains several elements. For certain user inputs (touch events), it happens that one element in the ListView calls invalidate() on itself. The problem is that sometimes, the element then redraws itself and sometimes not. When it does not redraw itself after invalidate() has been called, I need to scroll the ListView in order to get the desired redraw. Of course, I don't want that.
It is to mention that I never call listview.invalidate() but only element.invalidate(). Has anyone an idea on how to fix this?

As we all get older, we get wiser. My problem was that I did not use convertView in the Adapter's getView method but kept all the views in an ArrayList. Bad practice, ladies and gents. Use convertView and everything will work buttery smooth.

Related

RecyclerView: Race condition between notify* and scrollToPostion?

Is is possible to have race conditions between the notify* methods of a RecyclerView.Adapter and scrollToPosition (and smoothScrollToPosition) of the RecyclerView itself? If so, how can I force the scroll to happen strictly after the notify has been applied?
In a bit more detail: I have a RecyclerView with an adapter that frequently is updated with new items (which may or may not overlap with the previous items). Also, whenever I set new items I also want to set the scroll position to a specific item. To that end, I first update the items inside my Adapter and then scroll the RecyclerView.
However, more often than not the scroll position will be wrong after this process. Also, if I then issue another smoothScrollToPosition command without changing the data, the scrolling is weird: It sometimes goes in the wrong direction, etc. After this second scrolling, the position is always correct however. So, it seems that something goes wrong the first time and the RecyclerView catches and corrects that error on the second scroll.
Also, the errors are slightly different when I use notifyDataSetChanged from when I use DiffUtil.
Now I've read in this response by Yigit that notify* is basically asynchronous, so I suppose there can be a race condition between them and the subseqent scrollToPosition - is that correct?
Finally what can I do to establish a strict ordering, so that the scroll is only called when all ViewHolder updates triggered by notify are done?

Listview row requestLayout() and View recycling

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.

ListView getView() called too often

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.

Is the getView method of ArrayAdapter the best way of inserting custom views in ListView?

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).

First 6 ListView elements are continuously being invoked with getView()

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".

Categories

Resources