Android process death — and the (big) implications for your app
With more developers using Dependency Injection (e.g. Dagger) in Android and adopting patterns such MVP or MVVM, this topic is more needed than ever. There is a recent spike in use of what I would call “hidden Singletons”, the same anti-pattern just bundled differently.
Your Android application (process) can be killed at any time if it’s in paused or stopped state. The state of your Activities, Fragments and Views will be saved. When your return back to the application — the system will start the process again, recreate the top activity (the Activities in the back-stack will be recreated on demand when you go back) and you will get a Bundle with the stored state.
And here lies the issue some developers don’t fully realise — the whole process was killed. So any Singletons (or any “application scope” objects), any temporary data, any data stored in your “retained Fragments” — everything will be in a state as if you just launched the application. With one big difference — the state is restored, the user is at the point where he left the app.
Imagine, in your Activity you are depending on some shared Object, or some injected dependency where you keep recent data. Most likely the application will just crash on a NullPointerException because you didn’t expect the data to be in null.
How to test the application background kill & restore?
- Launch your application, open some new Activity, do some work.
- Hit the Home button (application will be in the background, in stopped state).
- Kill the Application — easiest way is to just click the red “stop” button in Android Studio.
- Return back to your application (launch from Recent apps).
- Crash? You are doing something wrong in your application :-).
By opening the app — the system will restore its’ state and the user will not even notice that actually the process was killed in the mean time. Well unless your application crashes because you were not prepared for it.
For this scenario it’s definitely not enough to just test your app with the “Don’t Keep Activities” options in the Debug Settings. This will just test if your activities can restore their state, but the process is never killed this way. The crashes will start coming in when you release your application, the users will open it and the leave it in background for a day and return back.
You can also set Background Process Limit to “No background processes” in Developer options. Put the application into background, launch any other application and then return back — application process will be restarted (the same as if killed due to lack of memory or battery saving).
Troublemakers in your app
- Any other shared instances that keep mutable data (such as injected dependencies where you keep some state)
- Data and State stored in your Application class
- Mutable static fields
- Retained fragments (state is restored, data is lost)
- Basically anything which is not stored in
onSaveInstanceStateand you depend on it
There is no single solution and it depends on the type of your application. Generally you should try to stay away from anything mentioned in the list, but that’s not always easy or possible.
You should be able to “reinitialise” the state — either load data from a database, SharedPreferences or reload anything needed again.
You may also have a login screen and timeout in your application — in that case it’s an acceptable approach to just detect the process kill scenario and forward the user back to the login screen.
Know the Android platform rules
Any architecture, framework or library has to play according to the Android platform rules. So anytime you see a new library or approach — think about if and how is it handling state restoration.
And as always — test your application for these cases. This particular issue is bad in the way that you will almost never see it during development and simple testing. But the end users will run into it regularly.
Follow me and read about possible solutions to this problem in the next article.