Couple of weeks ago, started to build a simple Android app for a friend. Been meaning to learn React Native for a while, so this was the perfect opportunity.

Things were going pretty well, was making good progress with the app until I realised the state of the app was lost when the user hits the back button.

Having done some native Android dev before, my first thought was that I needed to hook into the Android Activity Lifecycle and listen to onPause() to save the state, and then restore it when onResume() is called.

Thus began the search to figure out how to hook into the lifecycle with React Native. Given how integral the activity lifecycle is to Android dev, the search proved a lot harder than I thought. After a lot of searching, found two leads that looked promising:

  1. react-native-activity-android
  2. AppState

react-native-activity-android looked quite promising. It is a module written specifically to hook into the lifecycle (activityPause, activityResume). Unfortunately this module hasn't been updated in over a year, and was not compatible with the version of React Native I was using.

AppState is a React Native API. When I first looked into it, it seemed like it was roughly what I needed, but not quite. My understanding from the docs was that AppState would enable me to identify the current state of the app (active/background/inactive). Though what I needed was to take action when the app transitions (eg. take action in onPause() just before the app state becomes "background"). This meant that AppState would be one step too slow.

However, since react-native-activity-android didn't work, took a more detailed look into AppState and realised that it was actually what I needed. It allowed me to hook into onPause/onResume. Only realised this after digging into the code. From this commit c2d75d7a you can see the app's state is updated in onHostPause/onHostResume before sendAppStateChangeEvent is called. Therefore, if AppState says the app is in "background" this means that onPause must've been triggered.

With this discovery, I started looking into AsyncStorage as a way to store/restore state as required. However, after many hours of investigation and figuring out how best to use AsyncStorage and AppState, realised that hooking into the lifecycle was the wrong approach :(

In fact, what I really needed was BackAndroid. The default behaviour in React Native for the hardware back button is to exit the app. To prevent this, you needed to use BackAndroid to provide your own custom listener to override the default behaviour. One thing to keep in mind is your custom listener must return true otherwise the back button will still exit the app.

So after many hours of going down the wrong path, the solution to my problem was to add a simple 3 line custom listener via BackAndroid!

BackAndroid.addEventListener('hardwareBackPress', function() {  
  return true; // Back button disabled for entire app
});

If you're wondering, I did want to completely disable the back button, which made the listener was super simple. As frustrating as it was to find out how simple the solution was, at least now I know bit more about how React Native handles the Android Lifecycle.