How to Optimize & Improve Android App performance?

By Saurabh Barot   |   16 July, 2021
How to Optimize & Improve Android App performance?

The most important aspect of developing an Android app is its performance. Users are likely to reject your application if it is slow. The better your app performs, the more likely it is to succeed in the market. It’s critical to the performance people expect in a world where users are connected to their phones 24/7. if you’re wondering how to improve your android app performance, this is the right place for you.

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.

Statistic: Number of smartphone subscriptions worldwide from 2016 to 2026 (in millions) | Statista

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 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

The most recent version of Android Size Analyzer is available on Github as a TAR or ZIP file. After you’ve extracted the zip file run the size-analyzer script to see how big your files are (Linux or Mac OS). Alternatively, you can use the size analyzer.bat script (Windows) to run one of the following commands:


./analyzer check-bundle 
./analyzer check project  

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 WeakReference

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 this 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 tools like MAT, Eclipse Analyzer, 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.

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.

Preload Dex cache in Dalvik

When an app is installed, ART does a lot of pre-compiling. ART uses the on-device utility  tool (dex2oat)  to comply with apps during installation. This tool takes DEX input and converts it into a built app executable for the target device. This program will compile all DEX files that are valid without any problems. Some post-processing tools, on the other hand, generate incorrect files that Dalvik can tolerate but cannot be assembled by ART.

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" />

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.

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 dependiences

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

Don’t abuse the system

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 (FMS). 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 60fms target. If your app’s garbage collection time is 5 milliseconds you can see how much of an impact it has here.

Let’s look at what happens to the user if you miss the 16ms timeframe and receive a little different 58 or 59fms. So, what happens next? It has missed a frame and must now wait for the next one. Your app was rendered in 19 milliseconds, however, it missed the window, therefore the user is currently waiting twice as long.

Mitigation

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.

Don’t use any aspects of the UI that aren’t necessary for the first launch.

For hierarchies that can be expanded later, 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 cod.

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 when developing an application.

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.

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.

Make your Android App Market-Ready with Greater Performance?

Connect with Certified Android Experts

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.

Saurabh Barot

Saurabh Barot is co-founder and Experienced Chief Technology Officer at Aglowid IT Solutions. His deep industry experience in Angular, React, Ruby on Rails, PHP, Mean Stack and just to name few, has helped the company reach to a new level. He believes that technology is all about exploring new possibilities. Whatever a mind can think (exception can't be ruled out), technology brings it into reality.

Related Posts