0

My app consists of two activities: SignInActivity and MainActivity. SignInActivity lets the user sign in, and initializes a bunch of important variables the app needs to function properly. MainActivity contains a bunch of fragments that make up the actual app. These fragments use a MVVM architecture with ViewModels. The Fragment classes load information from their ViewModels to display on the screen.

One Fragment, AppleFragment, loads the type of apple (that the user previously inputted) by calling vm.getAppleType().getName(). AppleFragment then displays the type of apple on the screen. The user may only navigate to AppleFragment after he/she has set the type of apple.

Let's say a user presses the home button while using my app in MainActivity and AppleFragment. The app will be moved into the background and might be killed by the Android OS to save memory. If this is the case, and the user then goes to the Overview screen (i.e. the square button), and selects my app to open, Android will restart the Activity that was last open (MainActivity), and also the fragment that was last open (AppleFragment), but all variables (including the ones in the ViewModels) will be fresh - i.e. start from scratch.

Since AppleFragment loads vm.getAppleType().getName() in onViewCreated(), and the ViewModel is completely blank - remember Android destroyed everything to save memory - vm.getAppleType().getName() results in a NPE and the app crashes.

To mitigate this, I have MainActivity check if the important app variables have been initialized, and if not, start SignInActivity. The idea being that in the situation detailed above, the user would be redirected to SignInActivity, and the app would populate the important variables when the user signs in. The user would not be able to navigate to AppleFragment until they have set the apple type which the ViewModel can then give out to AppleFragment to display.

This approach doesn't work completely, because startActivity() schedules SignInActivity, but does not start it immediately - especially not until all of MainActivity's lifecycle methods have finished running. It seems that as part of MainActivity's onStart() method, the last viewed fragment, AppleFragment, is loaded. This is where we get into trouble because AppleFragment calls vm.getAppleType().getName() in its onViewCreated method leading to the NPE and app crash.

Flo We
  • 325
  • 2
  • 12
user1114
  • 1,071
  • 2
  • 15
  • 33

1 Answers1

1

From the docs:

If you don't need to store a lot of data and it doesn't require structure, you should use SharedPreferences. The SharedPreferences APIs allow you to read and write persistent key-value pairs of primitive data types: booleans, floats, ints, longs, and strings.

I think this should help with your problem.

I don't think it's ok to redirect the user to login again when the variables are lost. I'd recommend saving those values in the SharedPrefences. If you're concerned about security, you can read: Android SharedPreference security

89f3a1c
  • 1,430
  • 1
  • 14
  • 24
  • This is helpful, but not in this situation. The app stores quite a bit of data - > 1000 variables including complex objects like FireStore RegistrationListeners, lists, hashmaps, etc that can't be easily represented in shared preferences. – user1114 Jul 14 '19 at 02:55
  • But the user surely doesn't input so many data. You then calculate the data based on the user's info, I guess. You could redo that if the data is lost. – 89f3a1c Jul 14 '19 at 02:58
  • This wouldn't be preferred as project is on a tight deadline. Looking for a faster solution to implement. Thinking of overriding MainActivity's onStart method to call super.onStart() only if the app hasn't just been restarted in this situation. – user1114 Jul 14 '19 at 17:32