A performance question here. I have a recyclerView (in a fragment) that I'm populating from a database that's going to eventually hold around 16,000 items in a single table, 18 columns per record, nothing trickier than ints, decimals and varchars and the records are categorized so I don't expect to ever need loading more than, say, 300 at a time. Should I consider limiting the selects or implementing some sort of paging? I'd prefer to keep the recyclerView simple and seamlessly scrolling.
I'm also wondering about the recyclerView itself. The rows are rather complex and have two states: the default collapsed state shows 6 views including a single imageView, and upon clicking a row we get expanded state (a container goes from GONE to VISIBLE) with a total of 21 views including 2 imageViews. I care about the quality of imageViews so I'm testing it with a resolution limited at 512px for a small image (50% screen width) and 1024px for a large image (100% screen width), everything in JPGs. And because I need to track the state of rows, I have used
holder.setIsRecyclable(false);
in my onBindViewHolder in the recyclerViewAdapter, because without it expanding one row results in some of the following, recycled rows being expanded too. And I obviously want to have every row collapsed until explicitly expanded by user. So the thing is, the recyclerView doesn't scroll so smoothly, there is a noticeable scrolling lag as new rows enter the screen and the old rows leave it, or vice versa. When tested on a reasonably powerful device (LG G7 Fit) the experience is, frankly, quite jumpy. What can I do to optimize the performance (yes, I'm using 6 various sizes of images for various resolutions already). Is there perhaps a better alternative to the recyclerView that wouldn't need turning everything upside down?
FYI after an extensive testing I found that the most drastic improvement to the smoothness of scrolling is gained by reducing resolution of the images in the first (always visible) imageView.
Related
When displaying a screen with various sections ordered vertically, where each section looks different than the other (so maybe recycling items wouldn't use an actual recycle but a recreation), would be any true benefit to use a recycling view group, taking into consideration that no large bitmaps will be displayed, instead of an plain ScrollView?
I suspect there is a performance impact when using ListView for example, that might affect scrolling, and an slight increased memory usage, maybe a delay (only when layout is measured - not that often) when using ScrollView, but are these that significant for 7 sections, for example, where 3 of them are visible at a time?
Thank you!
This is mostly speculation, but I would consider it relatively well-informed speculation.
Let's assume you have 1000 sections, each of them different from the other. My understanding is that both ScrollView and ListView will have "problems" here, though the sort of problems they'll each have will be different.
ScrollView will measure and lay out all of its children up front (which will probably be quite expensive and will probably cause quite a delay in your UI). And it will have all of those views inflated and hanging around in memory (which might cause your process to crash with an OutOfMemoryError). But if the delay were acceptable and if you had enough memory for everything, at this point your app should run perfectly smoothly (i.e. no frames dropped when scrolling/flinging).
ListView, on the other hand, will only measure and lay out those children that are currently on-screen, as well as a few extras that are immediately off-screen. So initial performance should be quite fast and memory consumption should be quite low. But you mention that each section is "different", so view recycling won't "work". In practice, this would mean ignoring the convertView parameter of getView() and inflating a new view each time. If your sections are complicated, this could easily cause frame skips during scrolling/flinging.
But you mention that your app will have only 7 sections, or about 2.5 screen's worth of UI. For such a small number, I think worrying about performance before simply trying something out is silly; I suspect that a ScrollView holding a LinearLayout holding all seven sections would work perfectly well on all modern devices.
I have an XML file with about 150 views. Yes, I know it is a lot and I did get a message from Android Studio saying I can't exceed 80 views. But I can't drop views any lower than 150. I considered using list view but it works the way I wanted it to.
The question is, will this many views make the app crash/slow the device? I've tried it on my s7 and it works perfectly fine. My lowest API is 17 which is 4.2. Wouldn't 4.2 devices be able to handle this XML without any problem?
Thanks.
The problem with having an excessively large number of Views is that Android often needs to measure, layout, and draw them, and it will traverse the entire View hierarchy to do this. If the number of Views is so large that this traversal takes more time than the screen refresh rate, you will skip frames and your UI might appear to lag or be choppy.
If not all of those Views need to be on screen at once (for example, if you are using a ScrollView to hold a very large container that the user can scroll through), then you should probably switch to using RecyclerView.
If all of those views need to be on screen at once, then you might consider writing custom Views that can display your content all at once instead of having individual Views that draw individual things. This can drastically reduce the time and complexity of the measure/layout/draw traversals.
It's difficult to suggest an approach without knowing more specifics about your UI, but hopefully that explains the issue.
So, I've been developing on Android since about Feb 2011. One thing I've always been acutely aware of is that Nesting Linear Layouts with weight and weight sums is 'bad for performance' and the compiler (well at least eclipse did) thew a warning fit when ever you dd so.
However, it's been my experience that doing this has no noticeable impact on the user experience, or speed when switching screens. As an experiment I created the following screen which deliberately features nothing other than a mega O.T.T. use of weights and nested linear layouts. I've used contrasting colors to show all the linear layouts used. The benefits is that it looks the same on large and small screens.
I've tried it on a Galaxy S4, Galaxy Note 10.0, Galaxy note 3 7", and very small low powered Galaxy Neo. I've tried it on Gingerbread, Cream Sandwich, Kitkat and Lollupop and do not see any perceptible speed difference between this screen an a simple one with 4 buttons on a relative layout.
So what makes this such a bad idea? What is going on under the hood that makes this a less than idea solution? Will all this change the moment I add drawables or images into the mix?
The main issue here has to do with how Android positions your views on screen. Any time that a position changes with respect to a view, then a "layout" pass cascade through the view hierarchy, touching each view and performing some calculations (similar for changing "sizes" kicks off a "measure" pass).
Some layout containers, like RelativeLayout, have to force a 2nd "layout" pass to kick off; Once all the views have calculated their desired position, ReltativeLayout needs to then re-position everything again based on it's layout properties.
This causes a Double Layout Taxation trough the view hierarchy; which isn't free.
Now, if you have a shallow hierarchy, the overhead of this action is insignificant. Where this starts to run into a problem is when you've got a deep hierarchy, with multiple double-layout containers in it. For example, having a RelativeLayout at the root, which contains LinearLayouts that have "measure with largest child" set on it. The result is that the leaf-node views will have "layout" called on them ~8x times.
The performance impact of this is directly correlated to how complex your layout/measure passes are in your scene. If nothing is problematic, maybe a 12x-per-view layout pass isn't a big deal on high-end devices. However if one of the leaf nodes has a complex layout pass, well, then you're just wasting cycles.
The main topic here is to profile for things that are a problem, but keep in mind that setting things up the wrong way is just wasting performance that could be used elsewhere.
So what makes this such a bad idea?
It's not a bad idea. It is not free, either.
In particular, your scenario is fairly simple, despite your protestations to the contrary. While your layout is rather complex, it is rendered once. Hence, while you may drop a few frames while rendering it, that price is paid one time (or, more accurately, one time per activity/fragment that is using this layout).
Where per-layout expense becomes a much bigger problem is when it is magnified by having several of them that get animated around, such as rows in a ListView/RecyclerView, or pages in a ViewPager. Now, we are going through lots and lots of rendering passes, as the user swipes and causes us to redraw our content. Each individual row in the list might be significantly simpler than your layout, but we're also going to be trying to draw those many times per second. And, while a couple of dropped frames may not be noticeable in your case, dropped frames during animation is pretty much the definition of "jank" for an Android UI.
So long as you have no jank -- IOW, you are not dropping any frames, as reported by Choreographer in LogCat or as seen in the gfxinfo overlay through Developer Options -- then your layout is fine, at least as far as I and probably most users are concerned. Conversely, if you are dropping frames, trying to figure out more efficient layouts, perhaps even custom ViewGroups rather than general-purpose ones, may help alleviate that jank.
I have a GridView that displays images (7 columns of images that are 166dp x 249dp) that are all the same size (there are over 150 images), and I'm using the view recycling mechanism through the view holder pattern by way of an adapter. My views are all simply ImageViews. There isn't much going on that should be slowing the scrolling on this widget (there are 21 images on screen at a time), but the thing just scrolls so choppy. What can I do to speed it up?
I spoke with some of the boys at Google during the last Google Developer Lab and they told me that GridView is not maintained very much, and that I should use ListView, laying out the rows myself in code to make a grid. This is what I did and it's now lightning fast.
I have a very large image (a map) that I need to display. I already have the image in "tiled" format - 256x256 pieces.
Also I got tiles for several "zoom" levels.
At the moment the issue is to display the deepest zoom level, where you'd have really a lot of tiles.
For example, a medium sized map will contain 4 rows and 26 columns of tiles for deep level.
I tried approaching the problem using a 2 dimensional scroll view and image views inside it - 1 per tile.
The problems is that it crashes. When I try displaying 4 rows and 20 columns it doesn't crash, obviously it's a memory issue.
So the question here - how to display all that, taking into account limited phone RAM.
I do understand there should be a way to dealocate memory for images that are out of sight, and only display those which are currently in visible area of the scroll view, but I don't know how to do that.
Would be happy to hear any clues or maybe there's alternative approach to these things.
Thanks.
I think you might better use the grid view instead of arrays of scroll view (but I am not sure if it support side/updown scroll at the same time.
And then in your adapter, override the getView method. There you can control the recycling of your images.
The project I am doing also have issues with image and RAM, what I am basically doing is like:
image.recycle();
System.gc();
I tried doing the above stuff like 50fps with the image is like 800x400x32bit and still not running into out of memory issue. But if I take away the System.gc(), it crash immediately.