Defending Your In-Background App When Android OS Kills It
Android OS will kill your app in background to reclaim the resources and memory. Learn how to handle it as a developer.
It all started from a crash reported in Firebase Crashlytics console. Its been happening over and over again and giving very different logs on each occurrence. As an android developer on that project, I had to think very carefully on what might be the cause of this crash.
But before looking for the cause of the crash, reproducing the crash itself was important. I had to reproduce it somehow. Looking at the logs, I realized that there’s a globally static variable in the main
Application class, which is initialized at the launch time of the app. And now this is null.
How is it possible? This is initialized the first thing in the app when it starts. How can that be null then?
The answer lies in a simple word: Process Lifecycle. You can read more about it here.
Sometimes users press Home button to switch from your app to some other task they intend to do. Now your app is in background. Suddenly Android OS needs some memory and it looks in the inactive apps of the system. It sees that your app is in background for a while (say more than 30 minutes or so) and you have this big data stored as static variable in the memory. So, Android OS simply goes ahead and kills your app to reclaim that precious memory. And uses it for some other app in need.
Now, user comes back to your app by opening it from the Recent Apps option, and boom 💣. Your current Activity is using static data and expects it as a non-null data. You get a
NullPointerException . Firebase gets these crazy crashes with different logs each time because you never know at what screen user pressed home for some other app.
You need to be able to simulate this scenario and test how your app behaves. And fix any issues/crashes. Because this is a very common thing users do on Android phones.
But, how can you simulate this? How can you kill some app like Android OS does manually?
Android Studio comes with a simple button “Terminate Application” in the *Logcat *panel which kills your running debug app on emulator/device.
Usually, this helps in other cases but unfortunately not in this case. Pressing this button will completely kill your application process. And when you come back to the app from Recent Apps screen, the app will restart from the main launcher screen instead of the screen where user left it.
Simply go to the your Android SDK directory, and look for the
platform-tools directory. And open the terminal there and type this command.
adb shell am kill <PACKAGE_NAME>`
It must be noted that your app should be in background while running this command. If its in focus and foreground state, nothing would happen.
Please note that this is different than the command
adb shell kill. That command kills the whole process of your app like the Terminate App button while
adb shell am killonly kills processes that are safe to kill to reallocate resources such as memory, CPU etc.
If this is implemented and handled by developers carefully, this could be the very useful functionality from the user’s perspective. Because user would gain trust to your app and its resume supported capability with confidence that no matter how much times user presses Home, your app will remain intact and bold.
Here’s a simpler form of how can you simulate this case for debugging:
Key Takeaways & Actions for Developers
Taking from the Process Lifecycle guide from Android Developers website:
An unusual and fundamental feature of Android is that an application process’s lifetime is not directly controlled by the application itself. Instead, it is determined by the system through a combination of the parts of the application that the system knows are running, how important these things are to the user, and how much overall memory is available in the system.
As an android developer, you need to make sure that your app doesn’t crash or behave unexpectedly when Android OS reclaims some resources it while in the background or inactive state.
Here are some suggestions on how you can handle this case.
onRestoreInstanceState()methods to save the important data of your app before getting destroyed and loading it when user has brought the app back in focus.** This is the most recommended method to handle this case.** You can also store data in
SharedPreferences, or local
SQLitedatabase if the data can’t be stored in a simple
Bundleobject. Usually, making your data
Parcelablecan help you save/restore it without much persistent storage hassle.
You can also refresh data from the source such as network call to make sure that your data is valid and not null or corrupted. This depends on the app itself and its requirements, but this maybe a heavy option from the CPU or network perspective.
Or you simply restart the whole app from launcher screen. This won’t look good from the user experience as this would be unexpected to user and will make the purpose of putting your app in Recent Apps useless.
Have fun and use your code for good. 🙏
At the end, please Subscribe to my newsletter DroidUp to get more tutorials and tips on Android development directly in your inbox.