How to Optimize Android App Performance in 2024?

optimize Android app performance

Quick Summary:

Android app performance optimization is no easy feat. But it doesn’t have to be an impossible task either. With the right Android app performance testing tools and speed optimization best practices, you can improve Android app performance significantly. Here is the answer to your question – how to improve app performance in Android.

According to Statista, more than six billion people are using android phones today. Which will grow rapidly in the future. It makes no difference when, where, or how the content is accessed. The user expects constant stability in-app performance. If your application is slow and takes too long to load, the majority of users will abandon it.

 

The first step is to identify the root cause of the app’s delay. Once you’ve fixed the fundamental problem, you can give users a better experience. In this post, we’ll go over the steps you’ll need to take to improve the performance of your Android app.

Android App Performance Metrics to measure Android App Performance

Before trying to improve the Android app, we should first understand how to monitor your Android app performance. Understanding these Android app performance metrics will help you set a benchmark and better understand how much results your efforts to optimize Android app performance are yielding.

Android App Speed Metric #1- CPU Usage

First, you must keep an eye on your Android app’s CPU usage. Each app on a user’s device takes up a certain percentage of the device’s CPU capabilities. If your app takes up more CPU than generally expected of apps similar to yours, it will degrade the overall mobile app performance leading to users uninstalling your app. Hence, you need to optimize your apps to optimally use the user device’s limited resources, in this case – the CPU.

One of the biggest challenges in achieving this on the Android platform is that Android is an open-source OS used by almost all smartphone companies except Apple. Hence devices have different configurations and CPU capabilities. You should prioritize CPU optimization depending on what Android versions your users are most likely to be using.

Android App Speed Metric #2 – FPS – Frame Per Seconds (Janky Frames)

Another important Android app performance metric is FPS. Now, if you are into gaming or videography, you understand the concept fairly well. Frame per second tells how the end-user experiences your app on their device. For Android, your app needs to maintain a frame rate between 60-90 FPS for seamless and smooth performance. In Android terminology, this is known as Janky Frames – a situation where your app suffers due to slow UI rendering and is forced to skip some frames, causing a recurring flicker on the user screen.

Android App Speed Metric #3 – Memory Consumption and Management

All Android apps use up some memory when your app runs on the user’s device. Similar to the CPU, if your Android app uses more than the required memory, it could result in a memory error. Hence it is important to monitor your app memory usage and reduce it if it’s not in the optimal range. We have discussed ways to mitigate memory issues to improve Android app performance in the lower sections of this blog.

Android App Speed Metric #4 – Network Performance

If your app requires access to the internet, you’d need to ensure your app doesn’t suffer due to under-optimized network configurations. One of the biggest Android app performance bottlenecks is due to network errors such as unreliable Wi-Fi access points, network congestion, and weak or inconsistent network connectivity. A pro tip for ensuring your online Android app works fine on the network is first to build it strictly offline. This will ensure that your app functions properly even when net connectivity isn’t certain.

Android App Performance Metric #5 – Uptime and Latency

Latency is the difference between a user’s action and the returned response time of that action in your application. Naturally, higher latency has a negative impact on the user experience since it increases the overall load time of your Android app.

Android Performance Improvement Checklist

Let’s have a look at some of the options useful for your android app performance optimization. It contains the following items:

Let’s take a closer look at how to Check and Improve android app performance

1. Reduce  Application Size

One of the easiest way to improve your android app performance is by reducing the size of your application. Users in emerging markets, whether devices are connected to 2G/3G networks or are connected to a pay-by-the-byte plan, frequently avoid downloading applications that are too huge. This section will describe how can you reduce your android app size. Downloading such apps on a phone with a modest configuration would be a nightmare.

Mitigations

1.1  Publish  your  app  using  Android  App  Bundles

The easiest way to get rapid app size savings when publishing to Google Play is to post your program as an Android App Bundle, which is a new upload format that contains all of your app’s compiled code and resources but defers APK building and signing to Google Play.

It will create APKs that are optimized for each of the user’s devices. It will only download the code and resources that your app requires to execute. Although Google Play requires apps published with app bundles to have a compressed download size of 150 MB or less, following the advice mentioned here to make your app’s download size as short as possible is still a smart idea.

Note: Compressed downloads for apps you publish to Google Play by uploading signed APKs are limited to 100 MB or less.

1.2  Use Android Size Analyser

There are many android app performance tools. One of which is the Android Size Analyzer tool. That makes it simple to detect and implement a variety of ways for shrinking your app’s size. It’s available as a standalone JAR and as an Android Studio plugin. You can use it as a Plugin as well as a command line.

1.2.1  Using it as a Plugin

You can download Android Size Analyser Plugin using the plugin marketplace in Android Studio. To download the plugin using the following steps:

  • In Android Studio > Preferences
  • Select the plugins section from the left side
  • Click on Marketplace Tab
  • Click on Install

After you’ve installed the plugin, you’ll be able to use it. Analyze App Size in Analyze to run an app size analysis for your present application. Following the analysis of your app, a tool window emerges with suggestions for improving android app performance tuning.

 1.2.2  Using the Command Line

Following the completion of the development process, the APK analyzer command line tool offers direct insight into your APK. At android sdk/cmdlinetools/version/bin/apkanalyzer, apkanalyzer is a component of the Android SDK Command-Line Tools package.

Alternately, as explained in Analyze your build with APK Analyzer, you can utilise the APK Analyzer tool inside of Android Studio.


apkanalyzer [global-options] subject verb [options] apk-file [apk-file2] 

2.  Minimize Activity Leaks

Activity leaks or memory leaks, in general, are extremely dangerous. How does it happen?  If we keep a reference to an unused Activity in our code, we keep all of the Activity’s layout as well as its views. As a consequence, there are a lot of pixels you don’t want to store in memory. Let’s understand it with an example.

public class MainActivity extends Activity {
  //...
  Handler handler;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    handler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
              }
  }
}

We have an activity, and we have a handler within the activity. Handlers are thread-safe, have asynchronous communication, and all the wonderful stuff. But what happens if the handler.postDelayed causes post to be delayed.

So, what happens next? It signifies it’s alive as long as the handler has a message. And if the handler is alive, so is the enclosing activity. Even if you don’t require that activity, it will be in the memory. This is referred to as a memory leak.

Mitigations

Use Weak Reference

A weak reference is a reference not strong enough to keep the object in memory.  As the objects will be collected from memory, it will help you enhance android application performance.  Let’s take a look at the example code

public class MyClass {
    // 1. Create a WeakReference variable
    private WeakReference mAnotherClassReference;
    // 2. Set the weak reference (nothing special about the method name)
    void setWeakReference(AnotherClass anotherClass) {
        mAnotherClassReference = new WeakReference<>(anotherClass);
    }
    // 3. Use the weak reference
    void doSomething() {
        AnotherClass anotherClass = mAnotherClassReference.get();
        if (anotherClass == null) return;
        // do something with anotherClass
    }
}

Note the activity in the inner class is now referenced as  WeakRefrence.  Now, what will happen here?  Since the activity is referenced through Weak Reference it is collected through a garbage collector when activity stops existing.

Remove static references

In Java / Android static variables or constants will not be garbage collected.  It stays there once the class is uploaded via the Classloader. Since the class loader is not garbage collected your classes won’t be collected because they are referenced.

Consider employing an event bus to separate senders from listeners

When communicating from a service to an application, one of the most common use cases for the event bus model is to replace the LocalBroadcastManager. One advantage is that by bypassing the requirement to pass Intents, you may reduce a lot of code that is normally used to serialize or deserialize data.

Unregister your listeners.

Let’s say we have the following code and we have some Nastymanager which is, unfortunately, a singleton. And we add activity to this manager by addListener(this)

public class LeakActivity extends Activity{
@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  NastyManager.getInstance().addListener(this);
}

Here NastyManager holds activity. So let’s see how can you fix this problem. You can face this problem by simply unregistering the listener.

@Override
public void onDestroy() {
  super.onDestroy();
  NastyManager.getInstance().removeListener(this);
}

Here the Listener is unregistered by using the removeListener(this) command.

Prefer static inner classes to non-static ones

It is preferable to utilize static inner classes instead of nested classes with outer class references because they only refer to the global class object and not the instance object. Because any explicit references to other instance objects from the static inner class remain alive while the thread executes.

Do Code Review

If you have created the code that you are searching for memory leaks. Code Review can be the most effective way to find memory leaks.

Understand Application Structure

Understanding the structure of your program will aid you in determining the source of the memory leak. You need to understand the structure of your application in order to identify android performance issue.

Use Performance Monitoring Tools like LeakCanary

Although there are various options available to use in place of LeakCanary it is still a widely used Library. LeakCanary is a popular android app performance monitoring tool that runs alongside your program to monitor for potential memory leaks and dumps memory when necessary. It also notifies you of a clean and informative stack trace to help you locate the source of the leak or you could refer to the other tools like MAT, Eclipse Analyzer.

3. Consider Low configuration devices

It’s a good idea to keep low-configuration devices in mind while building apps. Every Android user is unlikely to have more than 2GB of storage space. Memory-intensive apps can have a significant impact on smartphones. Developers optimize their apps for the high configuration devices all the time. To maximize the android app performance, it’s a good idea to take into consideration a low-config device.

Mitigation

Trimmed  system_server  and  System UI Process

Changes made into system_server for android performance optimization are as follows:

  1. Previously, System Server performed all work in a separate thread started by the main process, i.e. Zygote; however, in Android 4.4, System Server no longer creates a separate thread and instead performs all work in the same Main thread with Looper support, making it easier to put a large number of Loopers in the android performance monitor efficiently.
  2. Previously, the System server would start all system services by default, but in Android 4.4, a series of on/off switches has been added to manage the launch of certain services as an optimization. If a System feature is turned off in the configuration, the corresponding System service isn’t started.

Validate Just-in-Time(JIT)-off option

Though it’s up to the developer to keep the JIT option on or to keep it off. There is another option also available “shared JIT”. These options will help you optimize the overall android performance.

Reduce font cache overhead for pre-process

The first attempt to retrieve fonts sends a request to the font provider, increasing the time it takes to lay out the first page. Pre-declare fonts that you want to retrieve in your manifest to avoid this delay. If retrieving a font takes longer than expected, the system will stop and utilise the default font.

Follow the instructions below to pre-declare fonts in your manifest.

1. Create a resource array in res/values/arrays.xml and declare the fonts you want to prefetch.


res/values/arrays.xml

<?xml version="1.0" encoding="utf-8"?>
resources>
   <array name="preloaded_fonts">
        <item>@font/font1 </item>
        item>@font/font2 </item>
    </array>
</resources>

2. Use a meta-data tag to delare the resource array in your manifest.

<meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts" />/code>

4.  Optimize Android Encryption Performance

SSL/TLS connections enable data-in-transit encryption. HTTPS uses TLS (Transport Layer Security) to encrypt network traffic. It’s an important part of improving Android app performance tuning. However, if they aren’t optimized, they can become a problem. Here are a few of the main reasons why it causes problems:

  • When you open a new connection, you must perform a new handshake, which slows down the process
  • Issues encountered during server-side encryption and client-side decryption

Mitigation

Use only a single handshake

The overhead for an application can be reduced by using a single handshake. The procedure will be slowed by using a fresh handshake for each connection, resulting in android sluggish performance.

Incorporate HTTP/2  and SPDY to reduce connection overhead

HTTP/2’s main goals are to improve latency by enabling complete request and response multiplexing, to reduce protocol overhead by compressing HTTP header fields efficiently, and to add support for request prioritizing and server push. Other protocol changes, such as improved flow control, error handling, and upgrade methods, are needed to meet these criteria, but these are the most significant aspects that every android app developer should be aware of and use in their applications.

Adopt other techniques such as OpenSSL,  Session Ticket, session caching, and so on.

By skipping straight to an encrypted stream when re-establishing a connection to the same server, an SSL session cache can save time, power, and bandwidth. This is a persistent cache that can span multiple application executions.

Also Read : Android vs iOS Security Comparison

5. Avoid Deprecation

Specific Android APIs may become obsolete or require refactoring with each version to give a better developer experience or enable new platform features. In certain circumstances, Android will deprecate the obsolete APIs and direct developers to new APIs. Let’s take a look at some classic examples of Deprecation.

  • Never call private API with reflection
  • Don’t ever call private native methods from the NDK
  • Don’t just use runtime.exe to communicate with the process
  • Abusing Private API is bound to lead to failure

APIs are generally deprecated to improve the security, stability, and performance of the android application.

Mitigation

Use proper APIs

Use proper APIs related to your application. Using unnecessary API can cause overhead to the system resulting in android slow performance.

Refactor your dependencies

Restructure your dependencies according to your needs and preferences. It doesn’t make sense to use the deprecated API.

Don’t abuse the system

Using the deprecated APIs will make it easier to abuse the system. It gives the entry point to the system allowing it to be abused.

Always be updated on your dependencies and tools

Being updated on your dependencies and tools will help you improve the performance of the android. It will optimize the API making the performance better.

6. Optimize Offline mode

Display whatever information you have while retrieving the essential data if your network is weak. It is recommended that the data be displayed in offline mode from the standpoint of usability and performance. Let’s look at the problems that could develop if caching isn’t used.

  • Data retrieval takes a long time due to bad network connectivity. (Which is a horrible application experience)
  • When there is no internet connectivity, it may be necessary to fetch data for offline support or to display previously fetched data.

Mitigation

Data Synchronization

Data synchronization between an Android device and a web server can make your app much more helpful and engaging for your users. Sending data to a web server, for example, serves as a valuable backup, while transferring data from a server keeps it available to the user even when the device is turned off. Users may find it easier to enter and amend data on a web interface and have it available on their device in some cases, or they may prefer to collect data over time and then transfer it to central storage space.

Managing sensitive data

Always determine access to sensitive data. Permission given to the application supports privacy by protecting access to sensitive information.

Permissions can be given for :

Restricted Data: Contact information, Bank Statements, or system state.

Restricted Action: Like Pairing to the Bluetooth device, recording audio, Taking Screenshots, etc.

Control shared data

Asking for a complex password every time isn’t a great idea in terms of usability. There should be some kind of authentication token to avoid this.  There should be control over the data that you share with other modules of an application.

7. Optimal Frame Rate

The maximum frame rate for rendering animations and gestures on iOS and Android is 60 frames per second (FPS). Anything slower than that will result in sluggish android performance.

Everything in the app’s rendering code should be executed within 16ms if you wish to accomplish the 60fps target. If your app’s garbage collection time is 5 milliseconds it can get really expensive on the app performance.

When your Android app misses the 16ms (an equivalent of 60fps) limit once, it becomes incapable of utilizing the window for that frame, leading to frame drops; so you get 58-59fps instead of 60fps.   The app still took  21ms to render, but it missed a window,  so from the user’s perspective, your app screen took twice as long to render.

Mitigation

Use Android Performance Tuner

We’ve figured out what the issue is. Let’s see what we can do to resolve the situation. Use Android Performance Tuner to ensure that each of your users has the greatest possible experience by measuring and optimizing frame stability and graphical consistency. It will assist you in identifying difficulties with performance and improving accuracy. Impact metrics assist you in categorizing and prioritizing concerns so that you may take appropriate action.

Advantage of using Android Performance Tuner

  • Scale the quality of user experience
  • Identify and prioritize the performance issues
  • Try getting the best options for each device

Pro Tip: You can add different modes to your application. Where users can select if they want Battery optimized mode or Best performance Mode.

8. Minimize App Launch Time

Users anticipate a quick and responsive app. People will have an unpleasant experience with an application that takes too long to launch, resulting in negative reviews on the Google Play store.

70% of mobile app users abandon an app if it takes too long to load. – Google

25% of users abandon apps after one use due to poor performance. – Uplands

Ultimately, the goal is to get the android app up and running swiftly.

Let’s take a look at the factors that helps speed up Android application launch time.

  • Installing many views
  • Excessive content
  • Bottlenecks in the initialization process
  • Layout

Mitigation

Use lazy initialization

Lazy Initialization is a performance optimization technique in which you postpone the construction of (possibly expensive) objects until just before you need them. One good example is to make a database connection only when you need to obtain data from the database, rather than right before you need it. The main reason for this is optimization so that you avoid generating the object if you never require it.

Avoid loading unnecessary UI elements on First Launch

Use placeholders for the hierarchies that can be expanded at a later stage of application. Using unnecessary UI elements will result in sluggish android UI performance.

Avoid memory disturbance due to memory allocation and garbage collection

Avoid having an issue while managing memory due to the dynamic allocation of memory and garbage collection. It may happen that the process is trying to get the resource but was not able to get any memory to allocate causing deadlock.

Fix synchronisation issue

Your data should be synchronized with the latest information of your system.  It will be great keeping usability in mind. If due for some reason you don’t have access to the real-time data but you have your app synchronized with the latest real-time data then the user will be in sync with the latest information.

Avoid using reflection

Using reflection should be avoided as It is slow, is fragile, and have security issues, it also has testing problems as you are replacing combine-time with run-time checking.

Always keep in mind that the app will perform differently on a cold and warm start.

9.  Improve Android  Layout performance

Layouts are an important aspect of an Android application since they have a direct impact on the design. If there are any errors or flaws with the layout, it will result in aggressive and slow apps.

The Android SDK contains tools that assist you in identifying android layout performance issues. With the help of the mitigation points below, you’ll be able to achieve android ui performance optimization with minimal memory footprint.

Mitigation

Resue the layout with <include/> and </merge>

You can utilize Android’s widgets to create small, reusable interactive elements, but you may also need to reuse larger components that require a certain layout. You can use the tags to insert another layout into the current layout to re-use whole layouts more efficiently.

Reusing layouts is especially useful because it allows you to develop sophisticated layouts that can be reused. A yes/no button panel, for example, or a custom progress bar with description text. It also means that any application pieces that are shared by several layouts can be removed, controlled individually, and then included in each layout.

For example here is the layout that defines the title bar included in each activity.


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/titlebar_bg"
    tools:showIn="@layout/activity_main" >
<ImageView android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:src="@drawable/gafricalogo"/ >
</FrameLayout>

Source: Android

Optimize hierarchy by analyzing and reviewing the layouts

You can achieve android app performance optimization by using Hierarchy Viewer that allows you to analyze your layout while an application is running. It will help you discover bottlenecks in the android layout performance.  Hierarchy Viewer shows a list of available devices and their running components. Because a nested LinearLayout slows down layout performance, flattening the layout making it shallow and wide rather than narrow and deep might increase efficiency.

Use Lint

Using the Lint tool on your layout files to look for any view hierarchy optimizations is also a good idea. Lint has taken the place of the layoutopt tool and includes several useful features. Lint examples include the following:

  • Use compound drawable: As a compound drawable, a Linear Layout with an Imageview and a Textview can be handled more effectively
  • Merger Root Frame: If a Framelayout is the root layout and does not provide background or padding etc, it can be made more efficient using a merge tag
  • Useless Leaf: Because it is invisible, a layout with no children or background can often be deleted for a flatter and more efficient layout hierarchy
  • Useless Parent: Layout with children that has no sibling is not a Scroll View or Root Layout, and does not have a background, can be removed and their children are moved to parent for more efficient layout hierarchy

10. Enhance Memory usage

To give the user the option of multitasking, Random Access Memory  (RAM) is required. An application’s RAM availability is limited by Android. These boundaries are not set in stone and are subject to change. Both the Android Runtime (ART) and the Dalvik virtual machine undertake garbage collection regularly. However, this does not imply that you may disregard when and where your app uses memory.

Mitigation

Avoid Memory Leaks

As discussed above, Keeping the reference to the unused activity is known as activity or memory leak.

Limit lifespan of services

You must keep the duration of each service to a reasonable level. It can cause a resource deadlock if it isn’t optimized properly. It’s always a good idea to keep the lifespan of services under control.

When users switch to a different UI, release UI resources

It’s a good idea to free up the resources that the previous UI was utilizing onPause and onStop callbacks when a user switches to a new UI. Database connections or Broadcast receivers are common examples of these resources. There will be less burden on the resources in this manner resulting in better android ui performance creating a seamless android app experience.

Utilize memory-efficient code

It is always recommended to use memory-efficient code to reduce the overhead on the system. Android tries to share some foundation resources or common classes in memory across processes to improve memory usage. As a result, when a device starts up, a process known as zygote loads the common framework code.

Reduce the use of external libraries

The trouble with libraries is that the user might also desire the dependencies. As a result, removing dependencies from the packed aar-file is difficult. If you have half of the library packaged to your library and the user needs a more recent version of the same library, this could lead to inconsistency.

11. Optimize Concurrency APIs

To design a scalable android app in a multicore device environment, the Android developer must be able to create concurrent lines of execution that mix and aggregate data from many resources. Unfortunately, developers frequently overlook the fact that services, methods, and activities all operate on the UI thread. If the APIs aren’t optimized, they’ll put a strain on the UI thread, slowing down the program.

Mitigation

Rather than concentrating on implementing Concurrent APIs. Take a look at the other alternatives listed below.

Intent Service

Asynchronous requests on-demand are handled by the Intent Service, which is an extension of the service component class. The service starts when it’s needed, handles the request via a worker thread, and then shuts down when it’s done.

Before Android 8.0: Before Android 8.0 Intent Service was used for the optimization purpose but it was deprecated in API level 30.

After Android 8.0:  After 8.0 (API level 26). It is recommended to use WorkManager or JobIntentService, They use jobs instead of services while running Android 8.0.

Async task

Async is designed to be the helper class around Thread and Handler.  It doesn’t constitute a generic threading framework.  This should ideally be used for short operations few seconds most.  It was intended to enable the proper and easy use of UI Thread. Async Tasks are defined by 3 generic types:

  • Pramas
  • Progress
  • Result

and is divided into 4 steps:

  • onPreExecute
  • doInBackground
  • OnProgressUpdate
  • onPostExecute

Executors

This package contains utility methods and factories for the Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, and callable classes. The following methods are provided by this class:

  • Methods for creating and returning an Executor Service and a Scheduled Executor Service, both of which can be configured with commonly used configuration options
  • Functions that build and return a “wrapped” ExecutorService, which inhibits reconfiguration by making implementation-specific methods inaccessible
  • Create methods that return a ThredFactory that sets the status of freshly formed threads
  • Methods that generate and return a callable from other clourse-like forms, allowing them to be utilized in execution methods that require callable

Understand APIs  and workarounds

Understanding the APIs you’re using will aid you in making your software more accessible and efficient. Learn the API method you’re using and be aware of which APIs are deprecated at all times. So that you may utilize the alternative given, understand it, and determine whether it meets your needs.

Map out correct solutions for the right problem

Any problem can be solved in a variety of ways, as we all know. The same is true when it comes to optimizing an android application. There are a variety of techniques to optimize applications, but not every approach is good and fit for your needs. As a result, always double-check that your problems have a proper and compatible solution.

Refactor your code

The primary goal of code refactoring is to improve the efficiency and maintainability of the code. This is the most important aspect of lowering technical costs and optimizing code. Refactoring improves readability and streamlines the android app performance testing and debugging processes.

12.  Adjust Architecture

The flaws that affect the lifecycle architecture are the most bothersome and evident. Learn the lifetime of app components, Fragments, and Flag surrounding activities to avoid these types of issues. It is strongly advised that you read the documentation. Keep your framework simple at all times. Working with the framework rather than against it is the best way to go. Framework components exist for a reason. Let’s have a look at some architectural concerns.

  • God Objects
  • Inheritance Abuse
  • Unclear Multithreading Boundaries
  • Neglecting Build Time
  • Flawed Modularization
  • Singleton
  • Not using MVX, Dependency Injection, and Pack-by-feature
  • Assuming a single screen

Mitigation

Avoid using your app’s entry point as a data source

The most important principle to follow is to avoid writing all your code in Activity or Fragment.  These classes represent the interface between the Android operating system and your app. Only the logic for OS system interaction and UI interaction should be included.

They can be destroyed at any time by the OS as a result of user interactions or system situations such as low memory. It’s best to reduce your reliance on them to deliver a satisfying user experience and a more manageable app maintenance experience.

Create well-defined boundaries between various modules of the app

It’s critical to provide clear boundaries between different android application components. It will come in handy when you need to add, remove, or test modifications to the application’s other modules.

Expose as little as possible

Applications become more vulnerable when they disclose their data and have sensitive information on them. By exposing data only when it is required, the application will be more secure and the amount of time it spends processing unnecessary data will be reduced.

If possible, test each app module in isolation

Testing each module in isolation will be helpful while you want to added, edit or test any new feature in your android application. You can check individual module performance with the isolation method without having an impact on overall application functionality.

Focus on unique core

Keep your app’s major focus on the one-of-a-kind concept it symbolizes. Always keep the fundamental logic of your program in mind while Android app development.

Single Source of Truth

Different REST API endpoints frequently return data. When the database is modified, callbacks on active LiveData objects are triggered. In this approach, the database is the only source of truth, and other parts of the software use our class to access it. Regardless of whether you use a disc cache, we recommend that your repository select a data source as the sole source of truth for the rest of your program.

13. Use Nested For-each loop instead of For Loop

For loop are quite versatile but they have some flaws as well. Let’s take a look at few shortcomings of For loop that can impact android app performance.

  • Lack of Clarity
  • Infinite Loops

Mitigation

For each loop or Enhanced For loop is another form of loop used to traverse the array It considerably reduces the size of the code and eliminates the need for a counter in the loop.  It optimizes the code saving resources and time.

According to Android Docs:

With collections, an iterator is allocated to make interface calls to hasNext() and next(). With an ArrayList, a hand-written counted loop is about 3x faster (with or without JIT), but for other collections the enhanced for loop syntax will be exactly equivalent to explicit iterator usage.

Also Read : How to Find App Developers for your Startup?

14. Use String Builder in place of String

Assume you have a String and you wish to append 10,000 more Strings to it for any reason. This is how the code would appear.

String string = "hello";
for (int i = 0; i < 10000; i++) {
    string += " world";
}

Due to the numerous trash collection operations involved in string concatenation, it might be inefficient. It will take around 8 seconds to execute the code. You’re probably wondering why string concatenation is so slow. Because the strings are immutable. This indicates that once something is made, it cannot be modified. Even if you think you’re changing the value of a String, you’re creating a new String with the new value.

The drawback of using String is that the value will remain alive without a reference until garbage collection.

Mitigation

String’s issues have already been revealed. Using String Builder, however, is a more efficient approach to reduce the overhead of memory.

StringBuilder sb = new StringBuilder("hello");
for (int i = 0; i < 10000; i++) {
    sb.append(" world");
}
String string = sb.toString();

This code will take about 5 milliseconds to execute. If you look at the CPU and memory visualization in Android Studio Monitor, you’ll notice that it’s practically flat. You’re adding tens of thousands of strings, which is unusual. However, if you do this,

String string = "hello" + " world";

It will work well after being converted to the string builder internally.

15. Autoboxing

The process of changing primitive type to Object type is known as autoboxing and unpacking. In practice, it translates int to Integer. Internally, the compiler employs the Integer.valueOf() function. Converting data types is not only time-consuming but also consumes a lot of memory. Let’s look at some code.

Integer total=0;
for(int i=0; i<1000000; i++){
total += i;

This code will take an average of 500ms. Rewriting this code will help you increase  android performance speed.

Mitigation

SparseIntArray

This problem can be solved by utilizing SparseIntArray or ArrayMap in place of traditional containers like Hashmap. SparseIntArray is discussed here. Intergers are mapped to intergers by SparseIntArray. Because it avoids autoboxing keys and values, it is more efficient. Furthermore, the data structure does not require an additional object for each mapping. let’s take a look at code.

SparseIntArray myArray = new SparseIntArray();
for (int i = 0; i < 100000; i++) {
    myArray.put(i, random.nextInt());
}

This solution will take roughly 2 milliseconds to complete, which is 25 times faster. Although the numbers may differ per device, it should still be much faster. Additionally, optimizing is a straightforward process. It’s entirely up to you to choose between SparseIntArray and HashMap based on your needs and preferences.

ArrayMap

Arraymap is a  generic key-value mapping data structure. It is designed to be more memory efficient than traditional HashMap. It keeps its mapping in an array:  An integer array of hash for each item and object array for key/value pair. This allows it to avoid having to create another object and also tries to control the size of the array more aggressively.

It should be noted that this implementation is not suitable for a data structure with a large number of values. The performance difference for containers carrying hundreds of data isn’t considerable; it’s less than 50%. Because these containers are designed to better balance memory usage and android performance, they will shrink their array as objects are removed from it, unlike most regular Java containers.

Android App Performance Best Practices:

Now that we understand how to gauge Android app performance, we should also know about the various best practices for improving the overall Android app performance. These best practices aren’t just limited to Android but could be used applied to any platform like React Native, Flutter, and others as well.

Android App Performance Improvement
Optimize Images and Videos

Any average Android app is bound to have some or the other sections where they need to use images and videos. The general misconception around image and video utilization in mobile apps is that you need to use the highest resolution file available.

Doing so, the images will take up a lot of space, increasing the overall size of your Android app. You must downsize and optimize your images and videos to suit your Android app requirements. More than size, higher res files will also use heavy chunks of users’ data, especially if they are on cellular networks with limited data plans.

Android App Performance Improvement
Network Request Optimization via Data Prefetching Prioritization

As we mentioned earlier, it is important to optimize network requests if your Android app is going to use the internet for downloading/uploading data frequently. Hence you need to prioritize what data is loaded first and if it should be loaded on cellular data or Wi-Fi.

Since users have limited mobile data, you need to optimize your app for optimal use. Moreover, Wi-Fi and mobile data both consume considerable device battery. A user needs to turn on the radio for Wi-Fi/Mobile Data to download any file on their mobile. Even after completing their download request, the radio stays active for 20-40 seconds based on the users’ carrier and device.

This can lead to unnecessary data consumption. Hence an ideal solution to avoid radio switching is to prefetch data that users might need immediately when opening the app. Prefetching can be set up as per your app and user’s dynamic needs; however, it is ideal for prefetching based on the user’s internet type (Wi-Fi, Cellular) and charging status.

Android App Performance Improvement
Managing Location Requests

Your Android app may need to collect the user’s location data to enable certain services. There are certain considerations to keep in mind as to how you set up your location requests to optimize Android app performance.

Firstly, you should only ask for a ‘precise location’ if needed. Probably apps like Uber, Google Maps, or Doordash are some apps that require users to consent for precise locations. However, if you’re working on a weather app, you don’t need to ask users for their precise location. A general sense of their surrounding area works just as well, in fact, better since using low-priority location details results in improved battery performance and faster network requests. You can set the location request via Google Location Services API to low priority by adding this line – LocationRequest.PRIORITY_LOW_POWER.

Alternatively, Android developers can use a sub-function in LocationRequest known as setSmallestDisplacement()and set this value to a few meters, which will skip notifying the user about location change if it’s within the defined range. Another important practice to optimize Android app performance is to make location requests only as and when needed. In the same instance as building a weather app, you won’t need to ask users for their location details now and then. Developers can use the setInterval() function and manually set the interval, after which your app would update the user location.

You should also ensure that you’re requesting location information only when needed. Unnecessary calls and requests, especially when the user is using your app in the background, won’t serve any purpose and drain your user device’s battery and network. One way to set this is to set up onPause() and onResume().

Android Performance Monitoring Tools
Apps to check Android App Speed

Most companies blindly follow Android app performance optimization best practices to improve their Android app performance without understanding their current capabilities and performance scores. To improve on something, you must first have a clear picture of your app’s capabilities, limitations, and other variables.

Luckily, Google provides many in-built Android app performance monitoring tools. There are also many globally trusted third-party best Android app performance testing tools that you can leverage to set Android app performance benchmarks for your project.

1. Android Vitals

Android Vitals is a useful Android app performance monitoring tool by Google that helps improve the overall technicalities of Android Apps on the Google Play Store. If your users opts-in when installing your app, their device’s log information regarding performance, stability, permissions, and battery can be aggregated via Google Play. It can then be used either with the Google Play Console displayed in the Android Vitals Dashboard or through the Google Play Developer Reporting API.

Google provides a bad behavior threshold that measures all sessions on all user devices to develop a bad behavior threshold that gets evaluated on a per-device basis. Developers can refer to these thresholds via Android Vitals.

Here is the Google Android Vitals Bad Behaviour Threshold per Google’s Android Vitals page.

BAD BEHAVIOUR THRESHOLD

Overall (avg. across all devices) Per phone model
User Perceived Crash Rate 1.09% 8%
User-Perceived ANR Rate 0.47% 8%

2. JankStats Library

As we already mentioned, one prominent Android app performance metric you need to check for is FPS – Frames Per Second. Jank refers to a situation where your Android app doesn’t render the UI in the ideal range of 60-90 FPS which causes visual lags and frame drops which ruins the user app experience. Google provides an official JankStats library for tracking and analyzing Android app performance bottlenecks. It provides a detailed report on any jank recorded on your app.

JankStats provides three essential features that help monitor Android app performance.

FrameMetrics: Firstly, it has the FrameMetrics API based on Android 7 – API level 24 and higher. If your targeted Android version is lower than Android 7, you could use the  OnPreDrawListener method as an alternate.

UI State: It is important to understand the context of any Android app performance issue to understand where the problem occurred, what activity triggered it, and how to replicate it. JankStats provides a state API that helps Android developers communicate with the library to get information on App Activity. The JankStats report will include the app’s present state in its jank reports.

Jank Heuristics: FrameMetrics only helps developers track frame durations but doesn’t assist in identifying the actual jank. However, it has internal mechanisms that can be set up to identify where the jank occurs, making the final Jank reports more useful and efficient.

3. Android App Benchmarks in CI (Continuous Integration)

Benchmark tests in Continuous Integration are one of the best approaches for tracking Android app performance and identifying potential performance improvements before your app is deployed on the Google Play Store. Though benchmark tests can be run on emulators that stimulate the hardware and software potential of specific Android devices, it is recommended to try and perform these benchmark tests on real devices to get the most accurate understanding of how your Android app will work on targeted devices.

4. Android Profiler

Android Profiler Tool replaces Android Monitor Tools for Android Studio version 3.0 or higher. Such Android Profiler tools can help developers get real-time data for gauging Android app performance regarding memory, CPU, network, battery, and other important user device resources.

5. Firebase Performance Monitoring

Firebase performance monitoring is one of the best performance booster app for Android, iOS, and even the web. It automatically records some of the most important Android app metrics if you add the performance monitoring SDK. These are:

  • Android startup time
  • Screen Rendering
  • Network Request
  • Firebase makes use of traces for collecting data about these processes. Trace contains data between two captured points at two different times in your app. These data points are known as metrics

Android Performance Challenges and Bottlenecks

It is important to identify and be prepared for various Android app performance challenges and bottlenecks to ensure the smooth functioning of your Android app. Android as a platform has challenges and limitations that developers must be prepared for. Here are some of the basic Android app performance considerations to keep in mind:

Android App Performance Challenge #1 – Device Fragmentation

One of the biggest challenges to optimizing Android app performance is device fragmentation. Android is an open-source operating software used by almost 7 out of 10 smartphones and devices to power their OS. Different companies apply different custom modifications to the base Android OS to create a unique value proposition for their customers.

The issue with this is since there are so many fluctuating hardware and software differences, delivering consistent Android app performance across all devices can take time and effort. The only workaround for Android fragmentation is to test your Android app on various smartphones of various smartphone companies and optimize Android app performance accordingly. Investing in many different smartphones/brands can be taxing, especially for SMEs and startups. Hence they can rely on emulators or real device clouds.

Android App Performance Challenge #2 – Software Fragmentation

At the time of writing, the latest Android version is Android 13. The biggest mistake most developers or clients make while optimizing Android app performance is to optimize it as per the latest Android version. By doing so, you might miss out on users that have Android smartphones with Android versions dating back to 6.0 or even lower. Optimizing your app for entry-level smartphones with older AndroidOS versions is a pro tip for improving Android app performance. If your app can run smoothly with those hardware and software restraints, it is bound to perform well on the latest Android versions.

Pro Tip – Identify your Android app users and try figuring out the average Android version and smartphones they are most likely to use. Optimize your Android app accordingly to avoid an unnecessary increase in Android app development costs.

Android App Performance Challenge #3 – Testing Fragmentation

Android apps can only be given a green flag to be deployed by passing proper Android app performance testing best practices. If you release your Android app without proper testing, it is most likely prone to bugs, cyberattacks, and other vulnerabilities. Again since there are so many Android devices, each with different specs creating a common test case for your Android app can be next to impossible. This is why it is advisable to consult with a professional Android app development company to ensure your Android app performance is at its peak and follows industry standards and best practices.

Final Thoughts

Finally, it’s worth noting that the globe has turned digital, and the number of linked devices is increasing at an enormous speed. At the same time, user attention spans are decreasing. The only way to keep them is for your mobile app to perform efficiently. This blog describes ways for improving an Android application’s performance. These strategies, when combined, can significantly reduce the amount of work that a CPU performs and the amount of memory that an application consumes.

have a unique app Idea?

Hire Certified Developers To Build Robust Feature, Rich App And Websites.

This post was last modified on August 2, 2024 5:40 pm

Saurabh Barot: Saurabh Barot, CTO at Aglowid IT Solutions, brings over a decade of expertise in web, mobile, data engineering, Salesforce, and cloud computing. Known for his strategic leadership, he drives technology initiatives, oversees data infrastructure, and leads cross-functional teams. His expertise spans across Big Data, ETL processes, CRM systems, and cloud infrastructure, ensuring alignment with business goals and keeping the company at the forefront of innovation.
Related Post