Android's Magic Number
Why you should care about lucky number 16
In Android, as in any interactive system, the choices you make matter. Every decision you make concerning the behavior of a component has the potential to affect other, seemingly unrelated components that might be a layout, a fragment or even an activity away. Within any application, over time things become interconnected, parts overlap and code is reused. If you don't fully understand how the system works, every choice you make has the potential to break everything.
Case in point: drawing. Drawing the widgets, views and layout you've painstakingly designed to the screen is a scientific process, with clearly defined parts and processes. But do you really know what they are? Do you understand how they work? Probably not. Because you probably don't really need to. But knowing just a handful of not-so-secret tricks might just make the difference between buttery-smooth scrolling lists and a janky stuttering mess.
One of these secrets is something I've mentioned a lot in the past: the simple, easy to remember number: 16. Sixteen is the number of milliseconds that you have to complete all your work so that every frame can be drawn. See, the screen on an Android device refreshes at 60Hz -- that's 60 times every second. To put it another way, for every second that passes, 60 frames are drawn to the screen (ideally). That means that each frame has to be completed in just 16 milliseconds. And you have to share those 16 milliseconds with cpu-gpu communication, the construction of display lists and a bunch of other under-the-hood junk that we don't talk about at parties. And if you can't manage that, every 16 milliseconds, for every single second that your app is in the foreground, what happens? Jank. Stutter. Whatever you want to call it, dropping frames appears as a choppy noticeable slowdown to the user. Those slick animations you worked so hard on won't actually get rendered in all their glory if you can't draw every frame, and scrolling an image-heavy list is going to skip and sputter all the way down to the bottom. If you have any of these problems, good news. There are lots of simple things you can do to get your house in order.
Flatten Your Layouts
As we say in Android, flat is the new black. Layout hierarchies have explicit depth. Each ViewGroup nested inside another comprises a layer of that hierarchy. The more layers there are, the more time it takes to figure out where everything is supposed to go. Each ViewGroup has to be traversed to find its nested Views and ViewGroups which have to be traversed, and so on all the way down. This is especially time consuming with RelativeLayouts, since they already need to be traversed twice... once to find all the views, and again to apply each view's relative rules to every other view. Nested RelativeLayouts in your list items are a sure fire way to consume precious milliseconds just inflating stuff. Flatten your hierarchies by removing nested RelativeLayouts and other unnecessary parent ViewGroups.
Offload the Work
If you're running animations or scrolling a list or grid, every millisecond counts. Things like image loading should be moved off the main thread even if you're loading them from a local resource. Libraries like Picasso will take all of that work off your hands with a couple simple lines of code. Trust me, if you're managing your own bitmaps, image caching and web requests, a library like Picasso or Volley will probably make your life a lot easier.
MVVP
MVP is a great pattern. It divorces business logic from platform-specific view operations, and nicely separates concerns. But depending on how much your raw data format differs from the UI design, formatting all your data on the fly can be a huge drain on performance. In this case, a slight modification of your MVP pattern might be in order. Basically, MVVPtakes your Model data and pre-formats it to match your View, so that all your adapter has to do when an item comes onto the screen, is put the right pieces in the right places. For data-intensive, view-recycling UIs, this is a great way to move work to the front and get it off your back.
Debug GPU Rendering
One last idea for just figuring out where you're going wrong in the first place is Android's built-in GPU Rendering debugger. To turn it on, go to Settings -> Developer Options -> Profile GPU Rendering. I could spend another entire article describing how it works and what it all means, but luckily the Android Developer Site has already done that for me.What I will say, though, is that if you're looking for some real insight into the performance of your application on a very granular level, check this tool out. Learning how it works and what it shows you is a great exercise not just in optimizing your app, but in understanding how the system at large really functions.
So that's it... just a quick refresh of some easy tweaks to shore up your data management and rendering performance. Take some time to think about these, so that your ListViews don't have to.