Press "Enter" to skip to content

Android Performance – Exploring Android Studio’s Powerful Tools

No matter how creative or efficient code you write if you are not aware of tools that can help you solve many problems, you are missing out on big and maybe writing boilerplate or creating your own library to achieve the task. So learning and knowing about the tools is as important as it is for code. In Android, most of the tools to get the work done is provided by Android Studio.

I am writing this blog post about the the things I learned in course by Google on Android Performance, which focuses highly on usage of tools provided in Android Studio. This course is available free on Udacity, and I think it is very important for anyone who is starting Android development, anyone who is in Android development but is unaware of performance tools.

The following blog will serve as summary of this course and will use original resources from the course itself and from Android Developer’s site.

This course divides the topics in four sections that is Render, Compute, Memory and Battery. Each section discusses problems arise in related areas and their solutions including tools provided by Android Studio. I’m going to discuss each of them in as short as I can with more focus on walkthroughs and tutorial so that you can get hands on experience whats going on.

These areas are:

  1. Rendering
  2. Computations
  3. Memory
  4. Battery

1. Render

One of the most common problem we face in rendering is lag. Lag is caused by frame skipping anything that takes more time than difference between two frames causes of frames to skip. This can be time consuming calculations or network calls, that holds UI to be updated.

Here is a video that shows how easily you can profile for rendering performance.

 

Overdraw – drawing objects again and again, for eg setting background of a layout then setting same background of view over it will cause to draw same thing.

Tool – GPU overdraw on device, will show how many times a view is rendered, from colors:

  • True color: No overdraw
  • Blue: Overdrawn once
  • Green: Overdrawn twice
  • Pink: Overdrawn three times
  • Red: Overdrawn four or more times

 

According to Google we should only allow blue color overdraw in our app, which means overdraw once only. According to developer guide, here is how to use overdraw tool:

  • On your mobile device, go to Settings and tap Developer Options.
  • In the Hardware accelerated rendering section, select Debug GPU Overdraw.
  • In the Debug GPU overdraw popup, select Show overdraw areas.

Now you should be able to see colors on the screen when you debug your app, a sample visual is provided by the original site as:

gettingstarted_image04

 

Where red color indicates too much overdraw, and the optimized way is on the right. Read more at developer site.

 

If you are using custom views you need to use clipRect (Canvas.clipRect) to optimize overdraw. This is used where the final image will not show something in the bottom layer you should clip that bottom view so it is never drawn in the first place. More on clipping:

Second issue that rendering has is nesting views. Nesting means creating a view inside a view. While, layout (or ViewGroups) are meant to be used like that, it should be only one child nested on the root ViewGroups. Namely, LinearLayout, RelativeLayout and ConstraintLayout etc. Unless there is a requirement for very complex UI we should still try to flatten the view hierarchy. We can analyze the hierarchy by using hierarchy viewer from tools when our app is running. To use this tool, make sure usb debugging is enabled on your phone and then run the app.

 

  • Select Tools > Android > Android Device Monitor. Android Studio might show a Disable adb integration dialog because only one process can connect to the device via adb at once, and Android Device Monitor is requesting a connection. So click Yes.

heirarchy_process

 

 

  • In the menu bar, select Window > Open Perspective, and then click Hierarchy View.

ADM_heirarchy

  • Double-click your app’s package name in the Windows tab on the left. This populates the panes with the view hierarchy of your app.

 

gettingstarted_image005

Here what you will see:

gettingstarted_image008

 

  • Tree View (center): Shows a tree view of your view hierarchy. You can drag and zoom the tree using your mouse and the zoom control at the bottom. Each node indicates it’s View class name and ID name.
  • Tree Overview (top right): Gives you a bird’s-eye view of your app’s complete view hierarchy. Move the grey rectangle to change the viewport that’s visible in the Tree View.
  • Layout View (bottom right): Shows a wireframe view of your layout. The outline of the currently selected view is red, and its parent view is light red.Clicking a view here also selects it in the Tree View, and vice versa.

To analyze nesting we start profiling by:

 

gettingstarted_image014

  • The left dot represents the draw process of the rendering pipeline.
  • The middle dot represents the layout phase.
  • The right dot represents the execute phase.

This interprets to:

  • Green means the view renders faster than at least half of the other views.
  • Yellow means the view renders faster than the bottom half of the other views.
  • Red means the view is among the slowest half of views.

So the greener the better.

There is a common issue when using this profiling tool discussed here. You can see the developer guide for more details here.

I came across this developer guide which at time was not in the course that I mentioned above, this is Systrace for UI. This tool has other features that can be used to analyze your android app’s performance. Follow official guide.


2. Computations

The code you write for your business logic can also cause application to be slow or even crash. These things can be:

  • Time consuming tasks like download or image processing
  • Bad code like wrong or no usage of batching or caching
  • Bad choice of data structures.

The batching and caching is discussed here which encourages developers to factor out the repeated tasks and do it once. In practical terms, less computations in loops will always result in better performance.

All the above can cause application to perform below par. These time consuming tasks should be done in background, the android system provides Thread class and also AsyncTask classes for these things. On a higher level there are free libraries like Retrofit2 for network related things and Picasso Library for image loading tasks that handle these issues very well.

Method Profiling – We can see how long methods are taking to do their job in Trace View, here is how:

  • Run your app, make sure USB debugging is on if you are using device.
  • Open Android Device Monitor following same steps as above.
  • Click on you running app from device window

ADM_heirarchy

  • Click on start profiling

ADM_heirarchy

  • Select profiling option

ADM_heirarchy

  • Sample Based: Will get trace every 1000 milliseconds, or your specified time interval.
  • Trace Based: This is more practical, it will show stats for each method that how much time it takes to do its work.
  • Do some work in your app, what ever code runs now will be traced.
  • When you are done simulating test scenarios, click on stop profiling.

ADM_heirarchy

Now what you see is trace log, double click the file title to view it in full screen.

ADM_heirarchy

You can see two windows, timeline panel (above) and profile panel (below) both these show same data, while the first one shows the trace graphically with respect to time. You can see from both windows the time it takes to run a method, number of calls, number of recursive calls, cpu time per call and lots of other statistics to help you analyze the cpu and time consumption your code does.

Find out more about traceview and how can you trace you own methods in traceview developer guide.

 

Another useful thing with traceview is you can add your own trace calls in the methods and specify the exact code line where it should begin and end. This is useful when you need to monitor your code or container objects. What are these? These are java objects which can have an effect on performance. Examples include HashTables, ArrayLists, Vector classes etc. To put it more simple, to analyze data structures that platform provides or user has defined, we can use this tool to find out what is going on under the hood.

This can be done, by adding begin and end methods from Trace class.

 

This guide helps understand how this code tracing works with a help of Recycler View Adapter and also how output will show from above trace code.

 


3. Memory

What are issues that may arise in memory management while writing android apps?

  • Memory Leaks, just as on any other platforms the concept is same here, objects that are not used anymore and Garbage Collector misses to clean them too.
  • GC overalls, the system cleaner that is clearing memory after every few while.

To avoid this we:

  • Destroy useless references, for eg broadcast receivers, interface references, listeners or any other object which may remain referenced even if parent object or its parent process is finished. This can be done by setting null to these objects or making calls to system provided methods like unregisterReceiver().
  • Avoid memory allocation when we can. Less variable/ object declaration and using already defined objects efficiently. Also use of local variable/objects is always encouraged since there lifetime is only the scope in which they are defined.

Following are the tools which allow us to analyze deeply the memory consumption in Android app.

  • Memory Monitor
  • Heap Viewer
  • Allocation Tracker

Memory Monitor is a tool that shows how your application is using memory over time. This is usually shown by default when you start debugging. See the tutorial here:

Usually, when GC is collected frequently and system always has to allocate more memory at GC calls this mean app has memory leaks. Why? Since GC is freeing up space and the app still wants more memory the previous allocations are not cleared in the memory.

 

Known Issue: Sometimes memory monitor or heap viewer does not show anything at all. This is because of, either app is not running or adb integration is disabled. Make sure that adb is enabled from tools menu.

enable adb

Heap Viewer shows what types of objects your application has allocated, how many, and their sizes on the heap.

  • Connect and start debug app after enabling usb debugging.
  • Go to Tools > Android > Android Device Monitor
  • From Device Window click your application

heaptaB

  • Click on “update heap”, this will dump (create) heap file.

update hgeap

  • Click on Heap tab, this will show results once you click on “Cause GC” button.
  • Go ahead and click on Cause GC.

cause gc

  • It will show you the objects that were in the heap memory.
  • Click on the object

heap details

What this is showing is the object that were tracked by heap in the last dump. You can analyze memory consumption and take respective decisions in your coding approach by looking at these reports.

If the garbage collector is unable to free large amount of space or in other words only few MBs of data is freed when you cause GC, there is a doubt that the code may be causing memory leaks. This will cause app to use more and more ram over time and ultimately crash. Freed memory snapshot:

heap details

 

 

Allocation Tracker shows details about object allocation almost same as Heap Viewer the main difference is that it has more details regarding allocation like allocation count than only allocated memory itself.

We use this tool in the scenarios like Memory Churn, that is when app allocates a lot of memory in short time, this can cause GC to call again and again and in turn frame skipping. So to analyze we go ahead and have a look at how can we use this tool.

  • Start memory monitor by running the app and clicking on Android Monitor at the bottom of Android Studio.
  • Select “monitors” tab.

mopnitors

  • Select start Allocation tracking

estart

  • Do something in your app, clicking, loading whatever your test scenario is.
  • Stop tracking by clicking on same button.

end

  • Now you have 2 views graph view and hierarchy view.
  • Go to your package name then your desired class name which you want to see allocation data.
  • Select the object in the class to see details.

navigate

You can also see more detailed allocation tracking stats from Android Device Monitor using this guide, but the one illustrated above is the easier way.

With these powerful tools you should be able to tackle most common memory leaks and memory related errors. And all of them comes within the Android Studio itself.

 


4. Battery

Since mobile phones have limited battery life which still a problem even in flagship phones, Android team suggests Developers to follow few best practices regarding battery usage. The phone battery drain spikes up when the phone is:

  • Using radio (the SIM network) over Wifi.
  • Wake locks (screen wake ups).
  • Location gathering, getting location with GPS.

To analyze battery we have a Battery historian project. What this do is take a log file from android battery usage logs and shows it in a graphical way. The battery historian script does that for you.

 

  • Download the open-source Battery Historian Python script from GitHub (https://github.com/google/battery-historian).
  • Unzip the file to extract the Battery Historian folder. Inside the folder, find the historian.py file and move it to the Desktop or another writable directory.
  • Connect your mobile device to your computer.
  • On your computer, open a Terminal window or open terminal in Android Studio from the bottom.
  • Change to the directory where you’ve saved historian.py,
    for example: cd ~/Desktop
  • Shut down your running adb server.
    > adb kill-server
  • Restart adb and check for connected devices.
    > adb devices

    If you don’t see any devices, make sure your phone is connected, and USB Debugging is turned on, and then kill and restart adb.
  • Reset battery data gathering.
    > adb shell dumpsys batterystats --resetResetting erases old battery collection data; otherewise, the output will be huge.
  • Disconnect your device from your computer so that you are only drawing current from the device’s battery.
  • Play with your app for a short time.
  • Reconnect your phone.
  • Make sure your phone is recognized: > adb devices
  • Dump all battery data. This can take a while:
    > adb shell dumpsys batterystats >  batterystats.txt
  • To filter out stats only for your app replace above command to add your package name

    > adb shell dumpsys batterystats > com.yourapp.package > batterystats.txt

  • Create a HTML version of the data dump for Battery Historian:
    > python historian.py batterystats.txt > batterystats.html
  • Open the batterystats.html file in your browser.

Known Issue: adb command unrecognized when adb is not set to path variable (in Windows) or environment variable on your machine. To resolve this add adb to the system’s environment variables. Follow this discussion if you do not know about system variables. You will also need python installed on the system if there is unrecognized command “python” error, and set environment variable for that too.

 

If you are able to see this image you have followed the steps right.

gettingstarted_image02

The python script converted a raw log file into a readable graph form by generating a HTML for you. Now you can see easily which operations are causing battery to drain more or less.

Source: Battery Historian Charts

 

Wake locks take up a lot of battery when they are triggered and its a common practice among developers to use wake locks from system’s Power Service when we want to show notification or say play media and keep device in wake state.

So what we can do is, we minimize the wake locks by using JobScheduler APIs, here is a good tutorial about JobScheduler API (link). What JobScheduler do is it will look for the most optimized time when your code should run.

For example if your task is battery intensive you write code and check that if phone is charging do the task else wait. JobAchedular API does these checks for you and in a scenario where you need location and network, JobSchedular encourages you you “schedule” a condition when the code will run instead of turning on Wifi and Location immediately. These conditions are as simple as “run this code when location and network is available” now you are not forcing the system to start location services or wifi.

Here is simple example, you create a service and set conditons:

 

Service class code:

And thats it.

Another approach would be the use of FusedLocationApi (visit here) introduced recently which also handles this more efficiently. Also if possible, move heavy computations to a web service so CPU will have less work todo and as a result it will consume less battery. For 3D graphics, the each game engine has is own guide to follow best practices to avoid any lag in game, so if you are using those engines it is recommended that you should have a look at guides provided by that platform.

 

I highly recommend to take the course and learn these concepts in more details, course link: Android Performance

Please feel free to leave comments, feedback or suggestions below.

 

Author: Talha

Talha is a CS graduate from University of Karachi, currently working at VentureDive as Software Engineer. He appreciates the use of best practices to reap full benefits of the given platform. He likes to question the conventional methodologies and practices and prefers to look at the bigger picture.

4 Comments

  1. Asad
    Asad February 1, 2018

    Very nice article 🙂

  2. Bugs
    Bugs February 1, 2018

    Amazing article!

  3. ΝΤΕΤΕΚΤΙΒ
    ΝΤΕΤΕΚΤΙΒ March 25, 2018

    Howdy, i read your blog from time to time and i own a similar one
    and i was just curious if you get a lot of spam responses?

    If so how do you reduce it, any plugin or anything you can suggest?
    I get so much lately it’s driving me insane so any
    help is very much appreciated.

    • kodesnippets
      kodesnippets March 26, 2018

      Hi, Nice to hear that. We use akismet for spam, and I think JetPack is also used for that purpose.
      Cheers.

Leave a Reply

Your email address will not be published. Required fields are marked *