Сохранить состояние приложения на 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(это андроиды собственной формы сериализации), то вы можете поместить его вoutStateBundleв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); } } }