Home > Devices > Fire Phone

Best Practices for Performance Optimization

Introduction

This page contains general guidelines and recommendations for optimizing the performance of apps that use the Fire Phone SDK.

Performance Tips for Dynamic Perspective UI Controls

This section helps you avoid some common mistakes with Dynamic Perspective UI controls that can impede the performance of your app. All of these controls are included in the Euclid SDK.

Shadows

Always use a ZShadowReceiver wrapped around a ZContainer to cast shadows from your Euclid controls.

ZHeaderNavigationBar

A full ZHeaderNavigationBar control with all components (title, secondary text, subtitle, Up button, and two Action buttons) can be expensive to render. You do not need to render all of these elements immediately as user starts your app. For example, you can choose to display only the title on startup to improve your cold start time. In this scenario, you would only specify the title in your layout XML and then add the remaining ZHeaderNavigationBar components programmatically after rendering the rest of your layout. In addition, you can improve performance by using secondary text only when necessary.

See Best Practices for ZHeaderNavigationBar for more information.

ZExtrudedText

Ideally, specify your text size just as you would for 2D text. The AutoSizing option for ZExtrudedText is expensive from a performance standpoint. Use the AutoSizing option sparingly, if at all.

To minimize your use of this option in your app development:

  1. Initially turn AutoSizing on.
  2. Build your app.
  3. Go to your hierarchy view to see the calculated text size.
  4. Use the calculated font size for your ZExtrudedText control.
  5. Turn AutoSizing off.

In addition, measuring text negatively impacts performance. If you set text width or height to wrap_content or match_parent, the onMeasure method becomes expensive.

ZContainer

Place all of your Euclid controls inside of a ZContainer. If possible, use multiple ZContainers for multiple Euclid controls in a sparse layout to best optimize your app's startup time.

Minimizing Activity Startup Time

This section contains tips for minimizing the startup time for your activity.

Optimize your Activity layouts

The following suggestions can help you optimize your activity layout:

  • Analyze your layout structure and try to arrange your views so that your layout hierarchy tree is shallow, rather than deep.
  • ZContainers can be costly to performance. If you have several Euclid controls that are physically near each other, group them into a single ZContainer. However, if you have Euclid controls that are far apart from each other and have non-Euclid content between them, group them into separate ZContainers.

Optimize your UI thread

Look at your onCreate() method and see if any part of it can be done asynchronously. Good candidates for asynchronous tasks are any service initialization, IPC calls, or database calls that do not block the UX. These tasks do not need to be working on the UI thread, and you can move this code to an asynchronous task.

Delay loading or cache your Views

Delaying or deferring loading your Views can generally help improve performance. You can also cache Views when appropriate:

  • You do not need to inflate all of your Views via onCreate.
  • Consider waiting to load some Views until they are explicitly requested by the user. This approach works best for simpler Views so as not to introduce a lag during a lazy load.
  • Defer loading left and right panels. For example Left and Right panels are usually hidden when the Activity first opens. Consider delaying inflating these views after your main page content loads using onResume(). Be careful about the delay interval so that user does not try to open left/right panels before they are initialized. If you choose to do this, test first to make sure that you do not encounter issues with complex views.
  • Consider leveraging a custom event/hook which can be fired from your fragment at a particular point in your lifecycle to perform delayed tasks. For example, if you are navigating to a page with a listView, you might have an event that fires after your adapter finishes binding/drawing, which will then trigger the creation of the left/right panels, toolbars etc. The event handler could reside in a common place to be re-used by all of your fragments.
  • Use ZPeekAlphaController to control your alpha changes.
  • Cache your Views by reusing existing frequently-used Views.

Object creation

Avoid creating unnecessary large objects during startup. Large amounts of memory consumed during startup can trigger garbage collection and slow the Activity startup time.

Load images asynchronously

Load your images asynchronously before displaying those images while other function calls are executed. Call requestImageState before your images are needed so that you can load them asynchronously.

Improving Memory Footprint and Avoiding Memory Leaks

The following suggestions can help you improve your memory footprint and avoid memory leaks:

  • Reuse your views when possible.
  • Use ZParallaxBackground to draw your background.
  • Do not hold long references to transient items. Transient items such as UI (Activities, Views, etc.) can cause significant memory leaks and bloat. For example, Views often hold context references, which means that you can leak entire Activity instances.
  • Be mindful of singleton instances. If you need to initialize or retain single app-long instances of things, consider what these instances hold. Ideally, hold only the minimum set of data that you need.
  • Use app contexts over Activity contexts when possible. In many situations, app contexts can be used in place of Activity contexts. References to the app context do not leak Activities.
  • Do not neglect to deregister your event handlers. Some event handlers can have a longer life than your app:
    • Listeners
    • Observers
    • Services
    • TiltPeekManager (MotionGesture API)
  • Clean up after your creations:
    • Asynchronous operations (handlers, runnables, threads, etc.)
    • Large objects that are no longer necessary such as bitmaps.
  • Cache objects only as needed. Caching objects is inherently a tradeoff between memory usage and fluidity / start times. Consider decreasing or restraining the size and scope of caches.
  • Remember that non-static inner classes hold references to their parent. Be mindful of what you store in a outer class when an inner class is present. Assume that both inner and outer classes have similar lifetimes.
  • Follow these guidelines when working with Runnables to prevent inefficient memory usage:
    • Try to extend your Runnable class, if possible.
    • If you need extended Runnables to be inner classes, make sure they are static inner classes.
    • Do not create Anonymous Runnables in any object that has a long-lived reference to an Activity or View that is in use. Avoid using Anonymous Runnables, unless necessary.
    • Consider using an AsyncTask instead of a Runnable when feasible.

Improving Fluidity

The following suggestions can help you improve your fluidity and avoid slow frame draws:

  • Minimize your use of dynamically created textures. Recycle textures when possible.
  • Do not block your app's UI thread.
  • Do not use a relative layout containing a ZContainer within list items in a Scroll or List View.