Как сохранить состояние при изменении ориентации в Android, если состояние составлено из моих классов? - PullRequest
52 голосов
/ 12 октября 2010

Я смотрел, как Android обрабатывает изменение ориентации моего приложения (я обнаружил, что он перезапускает основную активность при изменении ориентации. Я видел, что вы можете переопределить метод

protected void onSaveInstanceState(Bundle outState)

Чтобы сохранить материал, включите его. Проблема в том, что у меня есть мой вид с пользовательскими объектами и список с помощью специального адаптера. Все в ArrayList этих объектов, но я заметил, что вы не можете помещать произвольные объекты в пакет! Так как же сохранить государство?

Ответы [ 6 ]

137 голосов
/ 21 августа 2012

Вы пробовали использовать: его обход,

<activity name= ".YourActivity" android:configChanges="orientation|screenSize"/>

в файле манифеста?

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

Если вы напишите этот параметр, не нужно обрабатывать его в Activity, фреймворк позаботится обо всем остальном. Он сохранит состояние экрана или макета при изменении ориентации.

ПРИМЕЧАНИЕ Если вы используете другой макет для ландшафтного режима, при добавлении этих параметров макет для ландшафтного режима не будет вызываться.

Другой способ и Другой способ

42 голосов
/ 12 октября 2010

РЕДАКТИРОВАТЬ: В более новых версиях Android и с библиотекой совместимости сохраненные фрагменты обычно являются лучшим способом сохранить дорогостоящие для восстановления данные живыми при уничтожении / создании активности , И, как указала Дайанна, сохранение неконфигурационных данных предназначалось для оптимизации таких вещей, как создание миниатюр, которые приятно сохранять по соображениям производительности, но не являются критическими для функционирования вашей деятельности, если их необходимо переделать - это не заменяет правильное сохранение и восстановление состояния активности.

Но вернемся, когда я впервые ответил на это в 2010 году:
Если вы хотите сохранить свои собственные данные (без состояния просмотра), вы можете фактически передать произвольный объект специально для изменения ориентации, используя onRetainNonConfigurationInstance(). См. это сообщение в блоге разработчиков Android . Только будьте осторожны, чтобы не помещать никакие представления или другие ссылки на контекст / действие перед вращением в передаваемый вами объект, иначе вы предотвратите сборку мусора этими объектами, и в конечном итоге они могут исчерпать память (это называется утечка контекста ).

16 голосов
/ 12 октября 2010

Во-первых, вам нужно определить, что на самом деле является «состоянием» в вашем приложении. Вы не сказали, что на самом деле делаете, но позвольте мне предположить, что ArrayList объектов - это состояние, с которым работает пользователь.

Во-вторых, решите, каков жизненный цикл этого состояния на самом деле. Это действительно связано с этой деятельностью? Или пользователь не должен потерять его, если, скажем, его батарея разряжена, устройство выключается, и они позже возвращаются в ваше приложение? Если первое, onSaveInstanceState() правильно; если последнее, вы хотите сохранить в постоянном хранилище в onPause().

Для onSaveInstanceState() с пользовательскими объектами ключ заключается в реализации интерфейса Parcelable. Это включает в себя реализацию методов в Parcelable, а также создание статического объекта CREATOR в вашем классе. Вот код для типичного простого класса Parcelable:

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/ComponentName.java

Ключевые функции - реализация Parcelable:

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/ComponentName.java#317

и статический класс CREATOR:

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/ComponentName.java#355

(Статические writeToParcel() и readFromParcel() - просто удобства, которые были сделаны для этого класса и не требуются.)

Теперь, когда у вас есть это, вы можете поместить весь ваш ArrayList объектов в сохраненный пакет состояния с помощью Bundle.putParcelableArrayList:

http://developer.android.com/reference/android/os/Bundle.html#putParcelableArrayList(java.lang.String, java.util.ArrayList)

В Activity.onCreate() проверьте, есть ли у вас savedState Bundle, и если это так, попробуйте извлечь ArrayList из него и использовать его, если он найден, создав новый адаптер и представление списка для нового действия, которое используется для показать его.

3 голосов
/ 02 мая 2015

запишите свои объекты в строки JSON, используя Google Gson, а затем сохраните их как строку. Затем создайте их обратно из сохраненных строк JSON при восстановлении действия / фрагмента

import com.google.gson.Gson;

public class MyClass {
    private int a;
    private String s;
    private OtherSerializableClass other;
    private List<String> list;

    public String toJson() {
        return new Gson().toJson(this);
    }

    public static ChatAPI_MessagesArray fromJson(String json){
       return new Gson().fromJson(json, YourClass.class);
    }

    // Getters
    ...

    // Setters
    ...
}
3 голосов
/ 02 мая 2013

но я заметил, что вы не можете помещать произвольные объекты в связку!

Сначала создайте свои собственные объекты Parcelable.
Затем вы можете положить их в пачку.

Все в ArrayList этих объектов

Вы можете использовать метод putParcelableArrayList в связке для хранения ArrayList пользовательских «разбиваемых» объектов.

0 голосов
/ 26 июня 2019

Для простых данных действие может использовать метод onSaveInstanceState () и восстанавливать его данные из пакета в onCreate (), но этот подход подходит только для небольших объемов данных, которые можно сериализовать, а затем десериализовать, а не для потенциально больших объемы данных, такие как список пользователей или растровые изображения.

The ViewModel class allows data to survive configuration changes such as screen rotations.
Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI.

**Example**:

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

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...