Tia
Tia

Reputation: 2081

Keep application state on android

I am having trouble saving the state/singleton of my application.

When the application starts a loading screen (activity) is shown and a singleton is initialized with values from a webservice call (note that network access cannot run on the main thread).

After the singleton is created I open my main activity. Note that values from the singleton are required to build the layout.

Now assume the app goes in the background and is killed there (e.g. because of low memory). My singleton instance is deleted as the app is killed. When I switch back to my app it tries to recreate the main activity. As I mentioned earlier the values from the singleton are required to build the layout, so this leads to a NullPointerException (when I try to access members of the singleton, as it is not there anymore).

Can I somehow tell android to start the first loading activity after the app was killed? It would be great if I could refresh the singleton before the layout is recreated, but this seems to be a problem as network calls can not be on the main thread and therefore not block until the refresh is finished. I assume that I could save the singleton in all activities onStop and recreate it in the onCreate methods, but this seems a bit too unpredictable and would probably lead to a inconsistent state...

Another way could be to just always finish my activity onStop, but this would lead to losing on which tab the user last and so on, even if the app is not killed, so this is not a good option.

Any ideas on how to solve this?

Upvotes: 4

Views: 1940

Answers (3)

Tim
Tim

Reputation: 35923

Why not just use a SharedPreferences instead of a singleton?

Anytime you want to save some global state, commit it to preferences. Anytime you want to read the global state, read it back from preferences.

Then you don't have to concern yourself with application lifecycle at all, as your data will always be preserved regardless of what the phone is doing.

Upvotes: 4

soren.qvist
soren.qvist

Reputation: 7416

You could save your Singleton when onSaveInstanceState() in the Activity gets called. All you need to do is to make it implement Parcelable (it's Androids own form of serialization), then you can put it in the outState Bundle in onSaveInstanceState() which will allow you to retrieve it laver in onCreate() or onRestoreInstanceState() in the Activity, whichever you like.

I've included an example for you:

public class TestActivity extends Activity {

    private MySingleton singleton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState.containsKey("singleton")) {
            singleton = savedInstanceState.getParcelable("singleton");
        } else {
            singleton = MySingleton.getInstance(5);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("singleton", singleton);
    }

    public static class MySingleton implements Parcelable {

        private static MySingleton instance;
        private int myData;

        private MySingleton(int data) {
            myData = data;
        }

        public static MySingleton getInstance(int initdata) {
            if(instance == null) {
                instance = new MySingleton(initdata);
            }

            return instance;
        }

        public static final Parcelable.Creator<MySingleton> CREATOR = new Creator<TestActivity.MySingleton>() {

            @Override
            public MySingleton[] newArray(int size) {
                return new MySingleton[size];
            }

            @Override
            public MySingleton createFromParcel(Parcel source) {
                return new MySingleton(source.readInt());
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeInt(myData);
        }

    }

}

Upvotes: 0

rekire
rekire

Reputation: 47945

For something like that I used a pseudo singelton object as a Application class. This object will be created on the beginning and will be in the memory. But note that the system will terminate the application if the memory is needed by other applications. However this object is persitent even if all activities are temporally terminated.

To use that you need to declare that in your android manifest like here:

<application android:label="@string/app_name"
             android:icon="@drawable/icon"
             android:description="@string/desc"
             android:name=".MySingeltonClass"
             ...

Here is a code example:

public abstract class MySingeltonClass extends Application {
    // ...

    public void informClientOnline() {
        clientOnline=true;
        Log.v(LOG_TAG, "Client is online!");
    }

    public void informClientShutdown() {
        clientOnline=false;
        Log.v(LOG_TAG, "Client is going offline. Waiting for restart...");
        Timer t=new Timer("shutdowntimer", false);
        t.schedule(new TimerTask() {
            @Override
            public void run() {
                if(!clientOnline) {
                    Log.v(LOG_TAG, "Client has not restartet! Shutting down framework.");
                    shutdown();
                    System.exit(0);
                }
            }
        }, 5000);
    }
}

this two functions are called like this:

((MySingeltonClass)getApplicationContext()).informClientOnline();

Upvotes: 0

Related Questions