Optimizing ListView performance with complex items - android

I have a ListView with fairly tall and complex items but nothing too extreme. Each item is a CardView with a varying number of rows.
Unfortunately, it seems quite hard to make the scrolling completely smooth.
Even if the adapter's getView() method does pretty much nothing except returning the recycled view, there are frames above 16ms.
The slow frames have much slower draw times than other frames (such as 8ms) because the item is invalidated and drawn to cache when user scrolls to it (I assume).
I tried setting scrolling_cache to false, didn't help. Using a RecyclerView didn't improve the performance either.

First of all a ListView should not have a complex layout. If the ListView item can be expanded or something like that, there are other ways to do it. You might consider using ExpandableListView for this purpose.
But anyway, as your list item is a complex one, I ran through a similar situation earlier and I had to make the list item layout as simple as I could. I replaced all of my LinearLayout with RelativeLayout so that it reduces the View hierarchy.
If your list item (i.e. CardView) contains any image, you might have already considered using Glide or Picasso for loading the images.
Another trick I used once was to detect the fling scroll in the ListView using its onScrollListener for a complex list item.
#Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
if(scrollState != SCROLL_STATE_FLING) {
// Populate views here
}
}
Avoid any database calls or loops inside your getView function. You might have considered them already. I'm just putting my thoughts altogether.

Related

RecyclerView onBindViewHolder called multiple times for one item

I have used the RececlerView with the ViewHolder pattern for a while now.
Im am implementing a custom Adapter.
Im am not searching for a specific bug help in my code.
I was just wondering, if it's normal, that the onBindViewHolder method is called multiple times (for the same item) while scrolling to the end of the list and scrolling back up. In this case onBindViewHolder is called again for item 0 and 1 (the list contains 7 items in total)
Is there any possibility for this method to get called AGAIN without notifying that the datasat has changed?
Im a bit confused.
Kind Regards,
Palm
Yes it is perfectly normal for a RecyclerView to call onBindViewHolder() multiple times.
A RecyclerView only creates minimum number of Views needed to fill the screen. And it works by reusing the old/created Views. So that when you are scrolling down the View that hid during the scrolling to the top is removed and brought next to the last visible View and added there. But since the View is currently bound with old data onBindViewHolder() is called again to ensure that the View is bound with only the correct data before it is rendered.
Similarly you'll notice that onCreateViewHolder() is only called the exact minimum number of Views it needs.
For a better understanding of how the RecyclerView works I suggest you read up on Recycler, LayoutManager and Recycler.Adapter the three core parts of a RecyclerView.

Improve android listview performance for refreshing and scrolling

I have a ListView which onItemClick selected item changes its layout, pops different buttons. If any other item is selected, the previous selected one returns to normal. My ListView adapter works fine but refreshing the whole list with notifyDataSetChanged() in my adapter takes too much time.
My problem is to refresh only the changed items in the ListView.
And also I would like to have suggestions for better scrolling performance.
try to implement View Holder Pattern it increases the performance of loading and scrolling of ListViews
Making ListView Scrolling Smooth | Android Developers
Using lists in Android (ListView) - Tutorial - Vogella
from the docs:
Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById() is to use the "view holder" design pattern.
you can define one method in adapter class which will return current item view. in onitemclick use this method to make changes in clicked item. You can define class view type class variable in activity and store previous view there...
ListView scrolling performance slows down when widgests like textviews, images are at the bottom of the layout hierarchy.
So for improving list performance one should design item xmls with minimum layout tree levels.

scrolling become slow when having large number of textviews in scrollview

I have Scrollview is being filled pragmatically, with large number of textview with background Bitmap loaded from Assets folder. they are being filled as rows. each row has different number of columns, when i have large number of these textviews it scrolling stops to be smooth, i cant use adapter because i have multiple cases and each textview should have a seperate actions, how to make this scrolling more smooth?
I used Overidden text view and overided the :
#Override
public void requestLayout() {
/*
* Do nothing here
*/
}
but in the 1st load it still so slow, any ideas?
You can add the android:hardwareAccelerated="false" for a specific activity. http://developer.android.com/guide/topics/graphics/hardware-accel.html
I'd still go with the adapter and ListView design as you can inflate different layouts for each row just as you're doing already. The only difference is that the ListView will handle destroying and creating these views as they are required.
There's no need to make use of the convertView in the getView() method of the adapter if you will have many different types of view. But it should still scroll much smoother.

Should I use multiple ListViews?

I have a RelativeLayout with different elements. I was planning to have two ListViews on it, but I have noticed there are some problems with scrolling. Since each ListView only shows a maximum of 5 rows should I try to make some kind of custom adapter to merge those ListViews? Or is it better to replace the ListView with a LinearLayout/RelativeLayout and add the rows as I get them manually? (like the first answer in here: android listview display all available items without scroll with static header ).
Which should be the proper way on doing this? or is there another way? Also, each row will have an OnClickListener.
There's two solutions if you'd like to keep your list... list-y, without having to prerender all the row Views like the above solution suggests (which can be slow to render, eats RAM and doesn't scale nicely to more than a screen or two of Views, but is a fine quick solution for smaller lists, though I'd just use a bunch of Views in a LinearLayout in a ScrollView rather than a ListView in that case).
Write a custom ListAdapter, overriding getItemViewType, getViewTypeCount and GetView to inflate the proper kind of view and recycle appropriately for your two types of views. You'll also either need to override getItem to contain custom logic for figuring out which set of source data to look in and to map the data accordingly, or mush the data down into one list of Objects (if you're using an arrayadapter) and cast in the getView method (probably a bit slower than handling it in the getItem without casting).
Just use cwac-merge, a view-and-adapter wrapping adapter. You can put two ListAdapters into a MergeAdapter and set that as your single ListView's adapter.
I had problems with scrolling. I never figured out how to have the ListView share vertical space with a different View, and have a single scrollbar for them both.
I worked around it by having everything that needs to scroll on the layout a row in the ListView.
Adding views as rows to a LinearLayout may have problems scaling up, but I think you'll be OK if you only have 10 rows in total. On 1st gen Android devices it'll probably start to get sluggish around 20 items (depends on Layout complexity obviously). ListView scales up by only inflating views as they come on screen.
So in answer to your question either of the two alternatives you suggest will be OK, but the LinearLayout option will be the easiest to code.

How to avoid re-drawing all views in an ArrayAdapter

I have an ArrayAdapter powering a ListView. I would like to change the data behind the ArrayAdapter and update the ListView's. Sounds like notifyDataSetChanged(); would be exactly what I am looking for, but it updates the entire ListView, and I would prefer to update on a row-by-row basis.
Is there a way to do this with ArrayAdapter, or do I need to manage my data some other way if I want this functionality?
It doesn't work like that, as far as I know.
It will only redraw the visible rows. This happens when you're scrolling anyway. If you're scrolling down, and one of your rows (a View) goes off the top, Android reuses it if possible when drawing rows that come into view from the bottom. This is what the 3rd parameter (convertView) of ListAdapter.getView() is for.
I'm pretty sure Android only draws the rows that you're able to see in any case.

Categories

Resources