Сохранить состояние приложения на android


У меня возникли проблемы с сохранением состояния/синглтона моего приложения.

При запуске приложения отображается экран загрузки (activity) и инициализируется синглет со значениями из вызова webservice (обратите внимание, что сетевой доступ не может выполняться в главном потоке).

После создания синглтона я открываю свою основную деятельность. Обратите внимание, что для построения макета требуются значения из синглтона.

Теперь предположим, что приложение идет в фоновом режиме и убивается там (например, потому что низкой памяти). Мой экземпляр синглтона удаляется, так как приложение убито. Когда я переключаюсь обратно в свое приложение, оно пытается воссоздать основное действие. Как я уже упоминал ранее, значения из синглтона требуются для построения макета, поэтому это приводит к исключению NullPointerException (когда я пытаюсь получить доступ к членам синглтона, так как его больше нет).

Могу ли я каким-то образом сказать android, чтобы он начал первую загрузку после того, как приложение было убито? Было бы здорово, если бы я мог освежить синглтон перед тем, как макет будет воссоздан, но это, кажется, проблема, так как сетевые вызовы не могут быть в основном потоке и, следовательно, не блокируются до завершения обновления. Я предполагаю, что я мог бы сохранить синглет во всех действиях onStop и воссоздать его в методах onCreate, но это кажется слишком непредсказуемым и, вероятно, приведет к непоследовательному состоянию...

Другим способом может быть просто всегда заканчивать свою активность onStop, но это приведет к потере на какой вкладке пользователь последний и и так далее, Даже если приложение не убито, так что это не очень хороший вариант.

Есть идеи, как это решить?

3   4  

3 ответа:

Почему бы просто не использовать SharedPreferences вместо синглтона?

Всякий раз, когда вы хотите сохранить какое-либо глобальное состояние, зафиксируйте его в настройках. В любое время, когда вы хотите прочитать глобальное состояние, считывайте его из настроек.

Тогда вам не нужно беспокоиться о жизненном цикле приложения вообще, так как ваши данные всегда будут сохранены независимо от того, что делает телефон.

Для чего-то подобного я использовал псевдо-сингелтонный объект в качестве класса Приложения. Этот объект будет создан на самом начале и будет находиться в памяти. Но учтите, что система завершит работу приложения, если память потребуется другим приложениям. Однако этот объект является постоянным, даже если вся деятельность временно прекращена.

Чтобы использовать это, вам нужно объявить это в вашем манифесте android, как здесь:

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

Вот код пример:

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);
    }
}

Эти две функции называются так:

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

Вы можете сохранить свой Синглтон, когда onSaveInstanceState() в деятельности получает призвание. Все, что вам нужно сделать, это сделать это реализовать Parcelable (это андроиды собственной формы сериализации), то вы можете поместить его в outState Bundle в onSaveInstanceState() , что позволит вам получить его умывальником в onCreate() или onRestoreInstanceState() в деятельности, в зависимости от того, что вам нравится.

Я включил пример для вас:

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);
        }

    }

}