Singleton Object Becomes Null After App Is Resumed

Singleton object becomes null after app is resumed

You're getting crashes because you initialize those variables in one Activity, and expect it to be set always, in the other Activity.

But Android doesn't work like that, you can easily end up crashing because after low memory condition happens, only the current Activity gets recreated at first, previous Activity is recreated on back navigation, and all static variables are nulled out (because the process is technically restarted).

Try it out:

  • put your application in background with HOME button

  • click the TERMINATE button on Logcat tab

terminate button

  • then re-launch the app from the launcher.

You'll experience this phenomenon.

In Android Studio 4.0, after you use Run from Android Studio instead of starting the app from launcher, the Terminate button SOMETIMES works a bit differently and MIGHT force-stop your app making it forget your task state on your attempt. In that case, just try again, launching the app from launcher. It will work on your second try.

You can also trigger the "Terminate Application" behavior from the terminal, as per https://codelabs.developers.google.com/codelabs/android-lifecycles/#6, it looks like this:

$ adb shell am kill your.app.package.name

Solution: check for nulls and re-initialize things in a base activity (or in LiveData.onActive), or use onSaveInstanceState.

android exception in an activity makes all singleton fields null

When your app crashes then whole app process is restarted i.e. singletons also gets resets, you cant prevent your singleton becoming null when app crash but you can initialize when you app global application context is create.

make a class App.java

public class App extends Applications{
@Override
public void onCreate() {
super.onCreate();
initializeSingletons();
}

private void initializeSingletons(){
// Initialize Singletons.
}
}

and register this class in manifest

<application
android:name=".App" // Register here
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
.
.
.

This will guaranteed to call before everything i.e. before broadcast, activity, service etc. so you can be sure that your singletons will never be null when your app crashes and restarts.

When/why does my Java singleton instance get destroyed?

Each Android app runs in its own process so as long as it keeps running, your singleton will be available. When the process dies, your singleton is lost. Therefore when the app is re-launched this singleton object will need to be re-created.

Singleton Pattern - Splash Screen Not Launching After app being Killed (Memory Release) by OS Android

Why does this happen?

When the system kills your application to free the memory it saves a few pieces of data about the current state of your Application into the internal OS storage. Later on, when the user opens your app once again, the system takes that saved data from the storage and tries to restore the state of the Application.

The reason for that behavior is to make the user experience smoother. By restoring the state - the user can quickly continue doing things he was doing before quitting your application.

Some of the data that is stored in the OS storage:

  • Activities back stack (back stack of the Task)
  • FragmentManagers back stack
  • Bundle that you saved in the onSaveInstanceState methods

Please note: ViewModels are not saved between application re-creation. Even though they are saved upon Activity recreation(configuration change, such as screen rotation). So data that you store inside of your ViewModels (if any) would be lost!

In order to support this OS feature and ensure a smooth user experience in your application, you must design your application to not depend on any Launcher Activity to instantiate your singletons and instead use some other architectural approach that would not require your Launcher Screen to launch every time the application restarts.

What can you do?

You could try one of the following:

  • Save all the user input data (if any) to the Bundle in onSaveInstanceState method.
  • Migrate from Splash Screen Activity or Launcher Activity in favor of the Reactive approach to data instantiation.
  • Move your Singleton instantiation to Application class. Note: This could significantly increase the launch time of your application.

That is by no means an exhaustive list of actions you could do. I bet you would have better ideas that are applicable to your own application.

If migrating away from Launcher Activity is not possible at the moment, I suggest adding to your Activity onCreate method a check that everything is instantiated and ready to use. If not - immediately navigate the user to your Launcher Activity.

Please note: It would be good UX to save back stack and navigate back to the current activity as soon as your logic on Launcher Activity is done working.

Xamarin What happens to Lazy initialized singleton after App goes to background

Given that it is the webserver that is having the problem, stop it when app goes into background. Start it again when app returns (or lazy-start as needed).

Code might be something like this:

App.xaml.cs:

public static Webserver MyWebServer
{
get
{
if (_server == null)
{
_server = new Webserver(...);
}

return _server;
}
}
public static void StopWebServer()
{
if (_server != null)
{
_server.Dispose();
// So will be created again, on next reference to MyWebServer.
_server = null;
}
}
private static Webserver _server;

...

protected override void OnSleep()
{
StopWebServer();
}

Usage elsewhere:

... App.MyWebServer ...

If you don't want to make static variable (though IMHO that is okay for App, because there is only one, and its lifetime is that of the app itself), then remove the "static"s above, usage elsewhere becomes:

... (Xamarin.Forms.Application.Current as App).MyWebServer ...

static variable null when returning to the app

This is standard behavior in most mobile operating systems, definitely including Android. Your app is in fact very often killed if some other application with higher priority (generally, if it's in the foreground it's higher priority) needs the resources. This is due to the nature of mobile devices having relatively limited resources.

You should save your data somewhere more durable. You might find this article on general Data Storage to be useful. This question should be relevant too: Saving Android Activity state using Save Instance State

Note that this is in fact not a one-out-of-six device problem. This is a "problem" on all devices, it's just more apparent on one of your devices probably because it has less memory. If you run a very memory-intensive app on any of your other devices you should see the same behavior. Also there is no flag to prevent this. This is standard and expected.



Related Topics



Leave a reply



Submit