Hardware Layer for Android Optimization

Keywords: Android Mobile

More and more animations in the project, more and more effects lead to the application performance is getting worse and worse. How to improve.

brief introduction

Every frame needs to be redrawn in the process of viewing animation. If you use view layers, you don't need to redraw every frame, because View rendering can be reused once it leaves the screen buffer.

Moreover, hardware layers are cached on the GPU, which makes some animation operations faster. Hardware layers can quickly render some simple transitions (displacement, selection, zooming, color gradient). Because many animations are a combination of these actions, hardware layers can significantly improve the animation performance.

Three types of Layer type s are provided in View:

  • LAYER_TYPE_HARDWARE

    Indicates that the view has a hardware layer. A hardware layer is backed by a hardware specific texture (generally Frame Buffer Objects or FBO on OpenGL hardware) and causes the view to be rendered using Android's hardware rendering pipeline, but only if hardware acceleration is turned on for the view hierarchy. When hardware acceleration is turned off, hardware layers behave exactly as software layers.

    A hardware layer is useful to apply a specific color filter and/or blending mode and/or translucency to a view and all its children.

    A hardware layer can be used to cache a complex view tree into a texture and reduce the complexity of drawing operations. For instance, when animating a complex view tree with a translation, a hardware layer can be used to render the view tree only once.

    A hardware layer can also be used to increase the rendering quality when rotation transformations are applied on a view. It can also be used to prevent potential clipping issues when applying 3D transforms on a view.

  • LAYER_TYPE_SOFTWARE

    Indicates that the view has a software layer. A software layer is backed by a bitmap and causes the view to be rendered using Android's software rendering pipeline, even if hardware acceleration is enabled.

    Software layers have various usages:

    When the application is not using hardware acceleration, a software layer is useful to apply a specific color filter and/or blending mode and/or translucency to a view and all its children.

    When the application is using hardware acceleration, a software layer is useful to render drawing primitives not supported by the hardware accelerated pipeline. It can also be used to cache a complex view tree into a texture and reduce the complexity of drawing operations. For instance, when animating a complex view tree with a translation, a software layer can be used to render the view tree only once.

    Software layers should be avoided when the affected view tree updates often. Every update will require to re-render the software layer, which can potentially be slow (particularly when hardware acceleration is turned on since the layer will have to be uploaded into a hardware texture after every update.)

  • LAYER_TYPE_NONE

    Indicates that the view does not have a layer.
    //Default value.

Use

The first premise is that hardware acceleration is turned on in the manifest file. Otherwise, you will not be able to use hardware layer. This is also illustrated in the above document.

The API is also very simple, just use View.setLayerType(). Hardware Layer s should only be temporarily set up when used because they cannot be automatically released.
Basic usage steps:

  • Call the View.setLayerType(View.LAYER_TYPE_HARDWARE, null) method for each view that you want to cache during the animation process.
  • Execute animation.
  • At the end of animation execution, call View.setLayerType(View.LAYER_TYPE_NONE, null) method to clear.

Example:

mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);

animator.addListener(new AnimatorListenerAdapter() {  
  @Override
  public void onAnimationEnd(Animator animation) {
    mView.setLayerType(View.LAYER_TYPE_NONE, null);
  }
});

animator.start();  

But if using the above code in version 4.0.x would be a loss, setLayerType would have to be put into Runnable. As follows:

mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);

animator.addListener(new AnimatorListenerAdapter() {  
  @Override
  public void onAnimationEnd(Animator animation) {
    //This will work successfully
    post(new Runnable() {
        @Override
        public void run () {
            setLayerType(LAYER_TYPE_NONE, null);
        }
    }
  }
});

animator.start();  

If you are based on minSdkVersion 16 or above and use ViewProperty Animator, you can use the withLayer() method instead of the above operation:

mView.animate().translationX(150).withLayer().start();

Or use ViewCompat.animate().withLayer() when the API is above 14
In this way, your animation will become more fluent!

Matters needing attention

You know, it's not that easy.
Hardware layers have an amazing ability to improve animation performance. However, if abused, it will do more harm. Don't use layers blindly

  • First, in some cases, hardware layers perform more work than view rendering. Caching layers will take time, because the first preferred step involves two processes: rendering these views into a layer of the GPU, and then the GPU renders the layer onto Window s. If the View to render is very simple (for example, a pure color value), this will increase the unnecessary overhead of Hardware Layer at initialization time.

  • Secondly, there is a possibility of cache failure for all caches. Any time view.invalidate() is called during the animation process, the layer must be re-rendered. Frequently discarding hardware layers is worse than without layers, because hardware layers, as mentioned above, have extra overhead in setting up caches. If you need to re-cache layers regularly, that can be very damaging.

    This problem is also very easy to occur, because animation often has multiple moving parts. Suppose there is a three-part moving animation now:

    Parent ViewGroup
    —-> Child View1 (Move to the left)
    —-> Child View2 (Move to the right)
    —-> Child View3 (Upward movement)

    If you only set a layer on the parent layout ViewGroup, the cache will often fail, because the ViewGroup will change with the child View. For each individual sub-Views, however, they are just shifting. In this case, it's better to set Hardware Layer on each child view (rather than on the parent layout).

    Again, it's usually appropriate to set Hardware Layer on multiple sub-views so that they don't fail while the animation is running.

    Show hardware layers updates in mobile developer options are a powerful tool for tracking this issue. When View renders Hardware Layer, it should flicker green at the beginning of the animation (that is, when Layer rendering is initialized), but if your View is green throughout the animation, it's a failure problem.

  • Finally, hardware layers use GPU memory, and you certainly don't want to have memory leaks. So you should use hardware layers when necessary, just when you want to play animation.

There are no hard rules here. Android rendering system is very complex. As with all performance issues, testing is the key. Optimize the layers problem by using the "Display Hardware Layer Update" developer option.

Posted by vlcinsky on Sat, 01 Jun 2019 11:25:49 -0700