Проблема
Когда пользователь поворачивает устройство, система Android обычно уничтожает и воссоздает текущую активность. Вы хотите сохранить некоторые данные в этом цикле, но все поля в вашей активности при этом будут потеряны.
Существует несколько подходов. Если все ваши данные содержат элементарные типы, состоят из объектов класса String
или являются объектами класса Serializable
, вы можете сохранить их с помощью метода onSavelnstanceState()
в переданном объекте класса Bundle
.
Другое решение позволяет вернуть один произвольный объект. Для сохранения некоторых значений необходимо переопределить метод onRetainNonConfigurationl nstance()
, чтобы сохранить некоторые значения, и вызвать метод getLastNonConfigurationlnstance()
в конце вашего метода onCreate()
, чтобы увидеть, существует ли ранее сохраненное значение, и, если это так, присвоить свои поля соответствующим образом.
Обсуждение
Одно из решений - это использование метода onSavelnstanceState()
, которое уже обсуждалось здесь.
Альтернативное решение - использование метода onRetainNonConfigurationlnstance()
.
Типом значения, возвращаемого методом getLastNonConfigurationlnstance()
, является класс Object
, поэтому вы можете вернуть из него любое значение, которое захотите. Возможно, вы захотите создать объект класса Мар
или написать внутренний класс для хранения значений, но часто проще передать ссылку на текущую активность, например, используя следующий код:
public class MyActivity extends Activity {
...
/** Возвращает отдельный токен, который будет храниться
* между уничтожением и восстановлением объекта класса Enterprise.
*/
@Override
public Object onRetainNonConfigurationInstance() {
return this;
}
Предыдущий метод будет вызываться, когда система Android уничтожит вашу основную активность. Предположим, вы хотели сохранить ссылку на другой объект, который обновлялся запущенной службой, на которую ссылается поле в вашем объекте класса Activity
. Им может быть логическое значение, указывающее, активна ли служба. В предыдущем коде мы возвращаем ссылку на экземпляр класса Activity
, в котором могут быть доступны все его поля (даже закрытые поля, поскольку исходящие и входящие объекты класса Activity
имеют один и тот же класс). Например, в моем приложении для определения географических координат JPSTrack
есть экземпляр класса FileSaver
, который получает данные от службы определения местоположения. Я хочу, чтобы он продолжал получать координаты и сохранял их на диске, несмотря на поворот, вместо того чтобы перезапускать его при каждом вращении экрана. Вращение маловероятно, если устройство привязано к машине на приборной панели (как мы надеемся), но вполне вероятно, что во время определения координат пассажир или пешеход фотографирует местность или пишет заметку.
После того как система Android создаст новый экземпляр, она вызовет метод onCreate()
, чтобы уведомить новый экземпляр о его создании. В методе onCreate()
обычно выполняется активность, похожая на конструктор, например инициализация полей и назначение слушателей событий. Вам все равно нужно это делать, поэтому оставьте их без изменений. Однако в конце метода onCreate()
вы должны добавить некоторый код, чтобы получить старый экземпляр, если он есть, и некоторые его важные поля. Код должен выглядеть как примере 1.
Пример 1. Метод onCreate()
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
saving = false;
paused = false;
// Другая инициализация...
// Проверка, происходит ли прерывание, например при вращении
Main old = (Main) getLastNonConfigurationInstance();
if (old != null) {
saving = old.saving;
paused = old.paused;
// This is the most important line: keep saving to same file!
fileSaver = old.fileSaver;
if (saving) {
fileNameLabel.setText(fileSaver.getFileName());
}
return;
}
// Вспомогательная функция ввода-вывода
fileSaver = new GPSFileSaver(...);
}
Объект fileSaver
является крупным, поэтому мы хотим продолжать с ним работать, а не повторно создавать каждый раз. Если у нас нет старого экземпляра, мы создаем объект fileSaver
только в самом конце метода onCreate()
, поскольку в противном случае мы будем создавать новый объект, только чтобы заменить его на старый, который (по крайней мере) снижает производительность. Когда метод onCreate()
заканчивает свою работу, мы не ссылаемся на старый экземпляр, поэтому он должен иметь доступ к механизму сборки мусора Java. Конечным результатом является то, что активность, похоже, хорошо выполняется при поворотах экрана, несмотря на его воссоздание.
Альтернативной возможностью является установка атрибута android:config Changes = orientation
в вашем файле AndroidManifest.xml
. Этот подход предотвращает уничтожение и воссоздание активности, но обычно также предотвращает правильное отображение приложения в альбомном режиме и официально считается нежелательной практикой.