Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Была идея. Собрать в одно место группу важных переменных, чтобы вместе они стали чем-то большим. И когда понадобятся, могли использоваться тогда, когда программисту нужны значения не зависящие от жизненных циклов и высвобождения памяти свернутых приложений.
Идея
Идея появилась из проблемы. Проблема появилась из негодования.
Мне было жутко неприятно от мысли, что при повороте экрана приходится проделывать серьезную работу над тем, чтобы сохранить состояние экрана в том виде, каком оно было до поворота.
Но еще больше негодования у меня вызвала новость, что поворот экрана это не единственная причина, которая может мешать мне сохранять состояние в неизменном виде.
Я ранее слышал про то, что система подчищает ресурсы для чего-то, забивая на свернутые приложения, но когда я немного углубился в это, то очень сильно был огорчен. Именно из этого "негодования" у меня появилась проблема. Как мне сделать это красиво и не так болезненно?
И из этой проблемы появилась идея. Идея собрать все, что должно быть независимо от поворота экрана и высвобождения памяти, в одно место, чтобы я в этом месте был уверен на все сто процентов и всегда знал: Все, что я туда положил, там и останется в неизменном виде.
И не хотелось сильно размазывать код этими переменными...
Каким образом решить эту задачу? Сразу вспоминаешь решения, которые уже есть: bundle и т.д.
Но мне одному все эти решения кажутся неудобными? Мне одному кажется, что они выписываются из общего кода, когда начинаешь с ними работать?
И тут я встал перед выбором, либо я делаю принципиально что-то новое, либо я делаю обертку чего-то, что уже придумано. Да такую обертку, чтобы с ней было удобней работать.
После анализа возможностей и моего знакомства с SavedStateHandle я загорелся желанием сделать обертку над ним и все это использовать в MVVM. Так и родилась библиотека которую сейчас Вы увидите.
Реализация
Ну тут все просто (имхо)
Например, мы уже определились со скоупом наших значений, которые мы хотим хранить. Тогда просто создаем класс в котором просто декларируем их и помечаем этот класс аннотацией @Unkillable
Например вот так:
@Unkillable
data class SampleFragmentState(
val testValue: Double,
val testLiveData: MutableLiveData<Double>
) : EmptyState()
Также мы можем там указать и произвольные классы, но только они уже должны быть с Parcelize (Подробней).
Таким образом должен выглядить ViewModel. Естественно, библиотека предлагает не только работу с AndroidViewModel, но и просто ViewModel.
class SampleViewModel(
application: Application,
savedStateHandle: SavedStateHandle
) : AndroidStateViewModel(application, savedStateHandle) {
override fun provideState() = createState<UnkillableSampleFragmentState>()
}
UnkillableSampleFragmentState сгенерируется у Вас сразу после запуска билда проекта.
Естественно, наша ViewModel должна быть проинициализированна, но не совсем так как обычно. А так, как предлагает Google для использования SavedStateHandle.
activity?.application?.let { application ->
viewModel = ViewModelProvider(this, SavedStateViewModelFactory(application, this))
.get(SampleViewModel::class.java)
}
Это все. Теперь можно использовать по назначению! Просто записываем туда данные и достаем их. Отмечу, что для сохранения класса необходимо делать его @Parcelize (Подробнее тут).
Вот таким образом можно воспользоваться библиотекой.
init {
// get values example
Log.d("StateLog", "0 value ${state.testValue}")
Log.d("StateLog", "1 value ${state.testLiveData?.value}")
}
fun onSetDataClicked() {
// set values example
state.testValue = 2.2
state.updateTestLiveDataValue(3.3) // yourLiveData.value = 3.3
state.postUpdateTestLiveDataValue(3.3) // yourLiveData.postValue(3.3)
}
Таким образом, мы защищаемся от подчистки приложения из памяти операционной системой.
Итог
Цель данной библиотеки упростить разработку и разгрузить разработчика от написания кода, при условии, что он работает с сохранением состояния приложения. Также удалось очистить код от всех этих переменных, которые необходимо сохранить. К тому же теперь они логически отделены от общей массы и не засоряют код, что выглядит довольно приятно. Однако пока сейчас она работает только в MVVM от гугла.
GitHub