Ways to Prevent “ANR” in Android
Learn how to use different Android components, and follow coding guidelines to prevent ANRs. #ANR in Android , #How to Prevent ANR
A most important point to prevent ANR while programming Android!!
When developing Android applications, it’s important to prevent ANR (Application Not Responding) issues by using standard coding practices and offloading time-consuming operations from the Main thread/UI thread.
So the only single point to remember is that any resource-intensive or long-running task should not be running on the Main thread/UI thread.
What may be the Resource-intensive tasks for a process!!
- Image Processing
- Network Operations
- Database Operation
- Audio Video Processing
- GPS or Location related stuff
- Complex Algorithms
- Animation and Graphics Related functionalities
- Downloading large files
Never use the Main thread/UI thread for the task that comes under the above-mentioned categories!!!
It is important to regularly test your application’s performance and responsiveness to identify and address potential ANR scenarios. We’ll discuss the use cases for each component and ways to optimize code to minimize ANR.
Here are some strategies to use for implementing specific Android components, there are a few points to be considered whenever these components are required to implement a functionality. How to use them to prevent ANR in advance, ensure a responsive user experience in your Android applications and minimize the risk of ANR issues is achievable by following these best practices.
Use Background Threads for Resource-intensive tasks
We always need to think in advance if we are going to write an implementation of a functionality which is Resource-Intensive or long-running. We should decide on the task to execute in the background and which SDK API will be best to do this task as per Android guidelines.
The resource-intensive tasks are typically the operations that consume a significant amount of system resources such as CPU and Memory and they run for longer time and can block UI threads.
What APIs are available when performing tasks in the background in Java, Kotlin and C++?
JAVA!
In Java programming, when creating background threads, it is recommended to use either the Thread class or the Runnable interface. However, it is important to be cautious when synchronizing and communicating between threads. To efficiently manage a pool of threads, higher-level abstractions such as ExecutorService and ThreadPoolExecutor classes can be utilized. Additionally, CompletableFuture is a useful feature in Java 8 for asynchronous, callback-based programming and composing asynchronous operations. For Android development, AsyncTask is the best approach for executing background tasks and updating the UI thread with results, particularly for short tasks.
Kotlin!
Kotlin’s coroutine feature provides support for asynchronous and concurrent programming. It enables the creation of lightweight threads using the launch or async function. For Android development, it is suggested to use coroutines instead of AsyncTask for more modern and concise asynchronous programming. Furthermore, Kotlin also offers support for Java’s Executor framework, which provides a structured approach to managing background tasks. Tasks can be executed in the background using the ExecutorService and related classes.
C++
In C++, the std::thread class can be used to create and manage threads, but caution must be exercised when it comes to synchronization and resource sharing between threads. Another option for launching asynchronous tasks is std::async, which returns a std::future object that can be used to retrieve results or wait for completion. On Unix-like systems, platform-specific thread libraries such as POSIX threads (thread) can also be used. Lastly, high-level concurrency and parallelism constructs in C++ are offered by libraries like Intel TBB and Microsoft PPL.
Use Async Task or Executors API Carefully
AsyncTask is deprecated for Android SDK API 30 onward so we should use an alternative option of Async task that is Executors API with Handler.
The Executor interface may seem simple, but it is a highly adaptable and robust framework capable of supporting a wide range of asynchronous task execution policies. Defining tasks as Runnable offers a standardized approach to decouple task submission from execution. In addition, Executor implementations provide support for task lifecycle management, as well as for collecting statistics and facilitating monitoring and application management.
If you find yourself needing to implement a producer-consumer design in your application, using an Executor is likely the simplest approach.
Enhance UI Rendering and Minimize frequent UI updates
Optimize the XML layouts by removing unused views, reducing nesting, and using suitable layout parameters. reduce complex layouts with nested views and avoid overdrawing by optimizing the layout. Implement efficient view recycling and view holder patterns for optimal results. Avoid unnecessary view inflations and consider inflating it once and reusing it across the application. Use data binding or Live Data to update UI components in response to changes if updating the UI based on data change.
Optimize Bitmaps with Resize and compress images suitably to reduce memory consumption. Optimize animations and limit alpha transparency to ensure smooth transitions.
Use Hierarchy Viewer to analyze and optimize the view hierarchies and Android Profiler to monitor the application performance and visible components transition to observe the Janky frames.
Set Time Limits for operations for failed cases or error cases
Setting a time limit with fixed delays on particular time-bound tasks when the result can be different cases so handling the failed case and handling retry is not enough because we can not implement the infinite retrying for success cases. Hence, it is always a better idea to emphasize to the user with valid failure reason.
Use Strict Mode for logging the ANR policy violations!!
Strict Mode can detect coding problems such as disk I/O or network access on the application’s Main thread/UI thread. Strict Mode is a developer tool that enables the initialization of an application and observes the operations happening on the main thread. It can log violations to logcat when the violation has occurred. StrictMode can support preventing ANRs from occurring and make the Application transition smoother for better user experiences since you will be more informed of the potential problems in the application.
Code for better software performace!!!
Programming guidelines, Coding strategies, Debugging complexity, Code Quality, Specific Use of Several SDK APIs…..
Programming guidelines a key
It is always best to follow some Android programming guidelines and suggestions that boost the application’s performance and improve user interaction for a seamless UI transition.
Coding strategies
ANR is not a common exception that can be fixed all of a sudden with an Exception Handling block → Try {………} Catch{……….}Finally{………}. So, It is important to consider the ANR prevention strategies while writing the code if you are implementing the functionality where a resource-intensive task is required to implement.
Debugging complexity
ANR analysis and debugging sometimes require more time and may be more complex than we think. Fixing the ANR may require a large number of code changes, which certainly will not be easy always at the later stage of software development so we can use some debugging tools like LeakCanary or StrictMode to log the ANR detection traces.
Code Quality
Concentrating on the code quality and following the coding standards as per the operating system or used framework is not only for achieving the best performance, but It serves more benefits like reusability, maintainability, robustness, modularity and many more.
Even if a programmer puts all their effort into writing bug-free code, there is always a possibility that the final product will not work as expected in the first cycle.
That is why software development is an ongoing process that involves adding code, introducing new bugs, and resolving them repeatedly until the desired outcome is achieved.
Specific Use of Several SDK APIs
There are a few more topics which I would like to mention like implementing background services when required, handling network operations asynchronously and optimizing database operations also need to be implemented carefully to prevent ANR.
Summary!!
Throughout the article, we have been reading about various problems which may be introduced to the system by any small or big conceptual mistake or lack of consciousness toward optimization of source code. There is no concept in programming to write the best code, there are only best practices which need to be followed for the creation of software for the Users. Concerning the User perspective hazel-free and smooth-functioning software which provides the best user experience is best.
The motive of this article is not only to prevent ANRs, indirectly all points discussed above apply to not only Android-based applications but every operating system that provides the methods to perform the Resource-Intensive work outside the UI thread so the User input will not be blocked.
Any task which comes under the categories of Resource-Intensive work, Time-consuming task, or Heavy-loading task(all are the same) should be implemented in Background Thread by using the best Suitable API, Tool and Approach as per the standard guidelines of the Operating system and Programming language.
Thanks for Reading!
Please comment with questions and suggestions!! If this blog is helpful for you then hit Please hit the clap! Follow on Medium, Connect on LinkedIn, Follow on Insta and send emails if any discussion is needed on the same topic on copy email.
Thanks!! Android-World, Head First Android, Android Dev Notes, TUDO ANDROID, The Android Developer, The Funtasty Android Devs, Nikhil, Abhishek Pathak, Android Developers, Betul Necanli.