1

I am trying to use a static singleton DataManager that makes network requests and holds arrays of data for my Activity, instantiated in my Activity's onCreate() class, but the idea that the Activity gets destroyed every time there is an orientation change is tripping me up. I don't want to re-create a new singleton and re-populate it with data every time the user changes the orientation or comes back to the screen.

Even if I make DataManager a Service, if I make it a Bound Service, it seems like the Service will get destroyed whenever my Activity gets destroyed, but if I don't make it a bound service and use startService() and stopService() in my Activity, it also gets destroyed whenever my Activity is destroyed.

Also, if I use onSaveInstanceState() and onRestoreInstanceState() to save my instance of the singleton, it possible that my singleton would get destroyed when my Activity is inactive, since there is no longer a pointer to it. Then Activity B using the same DataManager class could create another DataManager instance while Activity A is inactive. Then Activity A wakes up, inflating another Data Manager, giving us 2 DataManagers that are no longer singletons and may have inconsistent data.

I have read elsewhere that I should not subclass Application to maintain app state, but I don't understand how it would work any other way. Thanks for any clarification.

newt
  • 199
  • 2
  • 12

2 Answers2

0

Subclass the application class and then instantiation your singleton within the application.onCreate() callback. This way it will be available for the lifetime of your application rather than the lifetime of a single activity. Careful that this won't be garbage collected until someone kills your app so don't have too many "Global" singletons.

FriendlyMikhail
  • 2,857
  • 23
  • 39
  • Just keep in mind that if the framework keeps the process around after your last activity exits, the `Application` instance will remain as well, and the same instance will be reused the next time you start the app without another call to `onCreate()`. – Kevin Krumwiede Oct 16 '15 at 19:39
  • My understanding is that this can be problematic and lead to NullPointerExceptions if the app is killed and an Activity is restored with a pointer that is no longer valid: [see this blog post](http://www.developerphil.com/dont-store-data-in-the-application-object/). – newt Oct 16 '15 at 19:40
  • Here's a discussion of best practices (rather than repeating them here) http://stackoverflow.com/questions/14057273/android-singleton-with-global-context – FriendlyMikhail Oct 16 '15 at 19:42
  • 1
    @newt If the process is killed, the `Application` will be recreated, so anything initialized in its `onCreate()` will be re-initialized. The problem comes when activities use the `Application` as a holder for data to pass to other activities. If the app is killed, the activity stack may be restored but the values in the `Application` won't be there. – Kevin Krumwiede Oct 16 '15 at 19:42
  • @KevinKrumwiede, OK that makes sense; so the Application creates the singleton every time, and the singleton fetches and holds the data, and the Activity only interacts with this singleton, so it will never point to any null values. But like MikeN said, if the application is never killed, then my singleton with all this data will remain, which I don't want. How to get around that? – newt Oct 16 '15 at 19:52
  • Handle that manually..destroy the data when you think it needs to not exist in memory anymore. Implementation details are up to you. – FriendlyMikhail Oct 16 '15 at 19:55
  • Ah, yes. I forget I don't need to worry about memory management since the Android OS does this. I don't think I would ever manually destroy the data, because the Activity UIs will be displaying it. – newt Oct 16 '15 at 20:01
  • 1
    @newt Right. The OS will kill the process if it needs the memory, so you don't need to worry too much about data hanging around in singletons. Just make sure they contain only data, not background threads. – Kevin Krumwiede Oct 16 '15 at 20:23
  • MikeN and @KevinKrumwiede, gruszczy's response seems to be the opposite of yours. Hard to get a definitive answer of best practices. I had seen that other Stack Overflow link you posted earlier MikeN, but that also had conflicting advice. Any thoughts in response to gruszczy's answer of not subclassing Application? – newt Oct 17 '15 at 20:40
  • Sure if your looking for best practices, I'd actually recommend using Dagger2, creating application scope singletons and injecting them where necessary. My initial answer was a less advanced way to solve the problem. – FriendlyMikhail Oct 18 '15 at 02:00
0

DO NOT do the work in Application.onCreate(). You will be slowing down your application start up, no matter what happens. This is not advised for Android applications, you want your app to start promptly.

Instead, if you really need a singleton, have it construct lazily when it's necessary.(If you are sure you will use it, you you can also force the construction asynchronously from a separate thread when your activity starts). When your activity gets destroyed, it doesn't mean the whole process will be immediately torn down, so your singleton will stay alive.

Also, if you are using a singleton, make sure to be able to clear it when memory is low. You will need to implement Application.onTrimMemory(int) and clear the singleton from there.

gruszczy
  • 40,948
  • 31
  • 128
  • 181
  • The problem is that even though the process most likely won't be torn down, there is no guarantee that the OS won't kill it, and kill the singleton. Can't I construct the singleton in the subclassed Application class asynchronously as well, so it won't slow down application start? – newt Oct 16 '15 at 21:32
  • You never have a guarantee that the process won't be killed (that's what I meant by saying torn down), so you need to write your app in a way to handles that properly. You might keep your singleton around as if it was cached to improve performance when there is a lot of memory, but you need to also take care of a situation where memory is scarce and your process will not stay long after the use is finished. – gruszczy Oct 16 '15 at 22:11
  • You can construct the singleton in the subclasses application, but you will slow down the application start anyway, because the separate thread and the main thread will compete for resources. – gruszczy Oct 16 '15 at 22:12
  • What I worry about in the situation where memory is scarce is that every time the user navigates away from the Activity screen, the Activity and singleton is destroyed, and when the user navigates back to the Activity screen, the app would have to instantiate all the data back into the singleton from the disk, which would be slow. In a low memory situation, what is preventing this from happening? – newt Oct 17 '15 at 02:13
  • There is nothing preventing that situation. This is the reality on low end devices. Be conservative about your memory use and make the startup as fast possible. There is no silver bullet that will fix that problem. – gruszczy Oct 17 '15 at 16:18
  • "You will be slowing down your application start up" - Yes, but probably only by a few milliseconds that no user will ever notice. And when Android kills your app to free memory, it completely destroys the VM. So it doesn't matter where you put the data; you're going to have to reload it the next time it's needed no matter what. Lazy initialization would only be advantageous if the data is often not needed by the activity. – Kevin Krumwiede Oct 17 '15 at 21:35
  • @KevinKrumwiede: Unfortunately this is a slippery slope. I had a doubtful pleasure of cleaning up `Application.onCreate()` which had a multiple singletons initiated that way and each took so little that the user didn't notice. Except when you added them all together, the user would clearly notice. This is a bad practice. Consider buying a phone for $50 and using it for day in-day out. You will very quickly start to appreciate fast start up of apps. – gruszczy Oct 17 '15 at 22:32
  • FWIW, I'm a professional Android developer with access to dozens of devices, plus five of my own. I regularly develop and test on low-end devices. When it comes to my own devices, I probably have less-than-average patience with badly-written apps. And I still think you're exaggerating both the importance of a fast startup time and the likelihood that a singleton will have any perceptible effect on it. But as always, YMMV. – Kevin Krumwiede Oct 18 '15 at 03:15