RenderThread is a new component that was introduced in Android Lollipop. The documentation about it is so scarce that at the time of writing this post there are only 3 references to it, and just one very vague definition:
A new system-managed processing thread called RenderThread keeps animations smooth even when there are delays in the main UI thread.
In order to understand what it really does, there’s a few concepts that need to be introduced…
When hardware acceleration is enabled, instead of executing the drawing calls directly on the CPU on every frame, Android uses a (hidden) component called “display list”: a recording of a set of drawing operations, represented by the class RenderNode (formerly DisplayList).
The benefits of going through such indirection are multiple:
The last point is precisely one of the things that the RenderThread is now in charge of doing: handling the optimisation and dispatching to the GPU, away from the UI thread.
....
Before Lollipop you might have noticed that animating view properties smoothly while doing “heavy” work, like transitioning between different Activity, was essentially impossible. And yet, from Lollipop onwards, those animations and other effects (like ripples) keep animating as if nothing was happening. The trick is a little help from the RenderThread.
The real “executor” of the rendering is the GPU, which by itself doesn’t know anything about animations: the only way to animate something is to issue different drawing commands at each frame, and that logic cannot run on the GPU itself. When this is done on the UI thread, any heavy work will prevent the new drawing commands from being issued in time, hence the lag in updating whatever is being animated.
It was mentioned before that the RenderThread can manage certain aspects of the display list pipeline, but it’s important to note that the creation and modification of the display lists still has to happen on the UI thread.
Then how can animations be updated from a different thread?
When drawing with hardware acceleration, the Canvas implementation is a class called DisplayListCanvas (formerly GLES20Canvas) which has overloads of some drawing methods that, instead of accepting a direct value, expect a reference to a CanvasProperty, which in turn is a wrapper for such value. This way the display list can still be created on the UI thread with a static set of drawing calls, but the parameters for such calls can be changed dynamically (and asynchronously on the RenderThread) through the CanvasProperty mapping.
There’s one more step: the value of a CanvasProperty needs to be animated through a RenderNodeAnimator, which is how the animation is configured and started.
Some interesting properties of the resulting animation:
Here is what can be animated through the RenderThread (so far):
It looks like Google wrapped only the drawing operations that it absolutely needed to provide the Material design animations we have today. It may seem very limited, but with a bit of creativity it could still be used to implement different animations, from variations of ripples to entirely new effects. The advantage of doing it this way would be guaranteed jank-free animations that are offloaded from the UI thread.
It seems like the capabilities of the RenderThread are going to be expanded in Android N (for example AnimatedVectorDrawable is going to be animated there) and maybe one day it will be released as a public API.