Как лениво сохранить SavedStateHandle ViewModel? - PullRequest
1 голос
/ 08 июля 2020

У меня есть экран, который загружает кучу запросов и собирает некоторые данные от пользователя на том же экране и во внешнем WebView. Поэтому у меня есть ViewModel, который содержит эти сложные объекты запроса (+ данные, вводимые пользователем). Мне нужно сохранить эти данные через завершение процесса, инициированного системой, для которого предназначен SavedStateHandle. Но я не хочу сохранять эти данные в базе данных, потому что они актуальны только для текущего пользовательского опыта.

Я интегрировал свои ViewModels с Hilt и получил SaveStateHandle. Поскольку у меня есть некоторые сложные объекты, к которым осуществляется доступ / изменение в нескольких местах кода, я не могу сохранить их «на go». Я заставил их реализовать Parcelable и просто хотел сразу их сохранить. К сожалению, у ViewModels нет такого метода жизненного цикла, как onSaveInstanceState().

Теперь я попытался использовать onCleared(), который звучал как нормальное место для записи в дескриптор. Но оказывается, что все .set() операции, которые я выполняю там, теряются (я тестирую это с помощью опции разработчика «Не сохранять действия». Когда я использую .set() в другом месте, это действительно работает). Поскольку ViewModel не привязан к жизненному циклу отдельного фрагмента / действия, а скорее к NavGraph, я не могу позвонить из их onSaveInstanceState().

Как / где я могу правильно сохранить свое состояние в SaveStateHandle?

1 Ответ

2 голосов
/ 08 июля 2020

Это именно тот вариант использования, который включает Lifecycle 2.3.0-alpha03 release :

SavedStateHandle теперь поддерживает ленивую сериализацию, позволяя вам вызывать setSavedStateProvider() для данного ключа, предоставляя SavedStateProvider, который получит обратный вызов saveState(), когда SavedStateHandle будет запрошено сохранить его состояние. ( b / 155106862 )

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

var complexObject: ComplexObject? = null

init {
    // When using setSavedStateProvider, the underlying data is
    // stored as a Bundle, so to extract any previously saved value,
    // we get it out of the Bundle, if one exists
    val initialState: Bundle = savedStateHandle.get<Bundle?>("complexObject")
    if (initialState != null) {
        // Convert the previously saved Bundle to your ComplexObject
        // Here, it is a single Parcelable, so we'll just get it out of
        // the bundle
        complexObject = initialState.getParcelable("parcelable")
    }

    // Now to register our callback for when to save our object,
    // we use setSavedStateProvider()
    savedStateHandle.setSavedStateProvider("complexObject") {
        // This callback requires that you return a Bundle.
        // You can either add your Parcelable directly or
        // skip being Parcelable and add the fields to the Bundle directly
        // The key is that the logic here needs to match your
        // initialState logic above.
        Bundle().apply {
            putParcelable("parcelable", complexObject)
        }
    }
}
...