Сохранить состояние приложения на android
У меня возникли проблемы с сохранением состояния/синглтона моего приложения.
При запуске приложения отображается экран загрузки (activity) и инициализируется синглет со значениями из вызова webservice (обратите внимание, что сетевой доступ не может выполняться в главном потоке).
После создания синглтона я открываю свою основную деятельность. Обратите внимание, что для построения макета требуются значения из синглтона.
Теперь предположим, что приложение идет в фоновом режиме и убивается там (например, потому что низкой памяти). Мой экземпляр синглтона удаляется, так как приложение убито. Когда я переключаюсь обратно в свое приложение, оно пытается воссоздать основное действие. Как я уже упоминал ранее, значения из синглтона требуются для построения макета, поэтому это приводит к исключению NullPointerException (когда я пытаюсь получить доступ к членам синглтона, так как его больше нет).
Могу ли я каким-то образом сказать android, чтобы он начал первую загрузку после того, как приложение было убито? Было бы здорово, если бы я мог освежить синглтон перед тем, как макет будет воссоздан, но это, кажется, проблема, так как сетевые вызовы не могут быть в основном потоке и, следовательно, не блокируются до завершения обновления. Я предполагаю, что я мог бы сохранить синглет во всех действиях onStop и воссоздать его в методах onCreate, но это кажется слишком непредсказуемым и, вероятно, приведет к непоследовательному состоянию...
Другим способом может быть просто всегда заканчивать свою активность onStop, но это приведет к потере на какой вкладке пользователь последний и и так далее, Даже если приложение не убито, так что это не очень хороший вариант.
Есть идеи, как это решить?
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); } } }