Android Activity Lifecycle considered harmful
Android process death, unexplainable NullPointerExceptions, and the MVVM lifecycle you need right now

The Android activity lifecycle is one of the first architectural concepts learned by a new Android developer. Ask any Android dev and they’ll likely all have seen this handy diagram from Google:

But what if I told you that the Android lifecycle diagram was in fact steering developers toward a design pattern that was fundamentally flawed?
This diagram above was one of the first mobile architectural decisions ever described and blogged about by Google. Early on, developers like Square noticed the challenges and difficult bugs attributed to issues with the Activity lifecycle. Over the years it became clear that the Activity lifecycle was designed before Google fully understood App Architecture.
The fundamental architectural problem comes when developers connect an activity with objects that are scoped to the lifetime of the application, such as Repositories. A common pattern might be to draw a view differently based on the presence of a Profile object for the currently signed-in user. For example, a view that renders a user name. Because a Profile object will almost certainly be provided by a Repository that has a lifecycle tied to the Application, not the Activity, as a developer you must consider what happens when a Repository is initialized (and a thus a Profile becomes available) both prior to, and in the middle of, your Activity lifecycle.
Uncertainty about when Application-scoped data is available influences when and how you initialize your Views, as well as when and how to initialize subscriptions to things like RxJava streams and LiveData.
What we found after 10 years of Android
At Perry Street Software, we have been publishing LGBTQ+ dating apps on the Google Play store for 10 years now. Our #1 crashing bugs were related to misunderstandings about timing and object initialization, rooted in our improper reliance on Android activity lifecycle methods and assumptions about application initialization that were true 95%, not 100%, of the time. If your Firebase Crashlytics is peppered with strange stack traces involving NullPointerExceptions
, and you aren’t intimately familiar with the concept Android process death, then you are almost certainly afflicted.
The Android lifecycle methods were never designed for a Clean MVVM architecture. Today at PSS, we don’t use the lifecycle methods for anything other than as an entry point for our own, custom lifecycle, something that we call the Clean MVVM Activity lifecycle.
With our architecture, we have clear answers to questions like “When do I setup my view?” and “When do I subscribe to this observable?”
“Where” Questions you’ve probably asked

We have already set a lot of rules in our MVVM architecture related to what belongs into each of the components, which makes the development of a new feature quite straightforward.
However, we haven’t discussed a lot about our View layer. We’re mostly describing the View as the layer which should react to state & event changes. Which raises some questions:
- Where do we initialize these subscriptions?
- How do we dispose them?
- Where do we instantiate our ViewModel?
- Where do we set up our views and click listeners?
- How do we handle deep links?
As an Android developer, you should be already familiar with the Activity / Fragment Lifecycle as seen above, but it’s not directly clear which lifecycle event should handle the questions we raised right above.
Does it matter?

One might argue, why do we need to overthink this? Does it really matter if we start our subscriptions or set up our views in onCreate()
or in onStart()
? Isn’t the user experience the same? Definitely not. Because of situations like Android process death, if you attempt to configure views by accessing application-scoped data — i.e., data that is shared between Activities and is likely attached to an object with an application-scoped lifecycle — you will eventually experience the dreaded NullPointerException
and your application will crash. Before we can explain why an alternative to the Android activity lifecycle is required, you need to first understand everything about Android process death.
UI testing is Hard
The worst thing about these issues is that we often can only discover them once we have shipped the code, because 95% of the time the app runs (and relaunches) in the same way. The formal solution — scripted exploratory UI tests — are often tedious to write, can break every time you have a UI or UX change, and may require special runtime environments (like AWS Device Farm), so our developers generally focus programmatic testing on business logic and entity layers instead of the view layer.
In the absence of robust UI tests, the best way to guard against these issues is to define a clear architecture for our View layer.
Next up
Before we argue for a new approach to working with Activity lifecycles, learn exactly what we mean by Android process death — why it happens and how to simulate.
Further reading
- Android Activity Lifecycle considered harmful ← you are here
- Android process death
- Clean MVVM Activity Lifecycle
- Repository Initialization
- Activity Lifecycle Cheat Sheet
- Debugging Android process death
Other series you might like
Clean API Architecture (2021)
Classes, execution patterns, and abstractions when building a modern API endpoint.
Kotlin in Xcode? Swift in Android Studio? (2020)
A series on using Clean + MVVM for consistent architecture on iOS & Android
About the authors
Eric Silverberg and Stelios Frantzeskakis are developers for Perry Street Software, publishers of the LGBTQ+ dating apps SCRUFF and Jack’d, with more than 20M members worldwide.