На этом шаге мы рассмотрим порядок выполнения такого преобразования.
Сериализация и десериализация сохраненного состояния работают исправно, но этот код можно улучшить. Обратите внимание, что сейчас надо вручную указывать ключ и тип данных (выполнять приведение к типу CharacterData), когда вы возвращаете и передаете CharacterData в savedInstanceState:
private const val CHARACTER_DATA_KEY = "CHARACTER_DATA_KEY" class MainActivity : AppCompatActivity() { private var characterData = CharacterGenerator.generate() override fun onSaveInstanceState(savedInstanceState: Bundle) { super.onSaveInstanceState(savedInstanceState) savedInstanceState.putSerializable(CHARACTER_DATA_KEY, characterData) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentView(R.layout.activity_main) val binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) characterData = savedInstanceState?.let { it.getSerializable(CHARACTER_DATA_KEY) as CharacterGenerator.CharacterData } ?: CharacterGenerator.generate() . . . . } . . . . }
Можно улучшить код, добавив объявление свойства-расширения в MainActivity.kt.
private const val CHARACTER_DATA_KEY = "CHARACTER_DATA_KEY" private var Bundle.characterData get() = getSerializable(CHARACTER_DATA_KEY) as CharacterGenerator.CharacterData set(value) = putSerializable(CHARACTER_DATA_KEY, value) class MainActivity : AppCompatActivity() { . . . . }
Рис.1. Объявление свойства-расширения в characterData (MainActivity.kt)
Теперь можно обращаться к characterData в сохраненном состоянии экземпляра как к свойству. Вам больше не нужен ключ для извлечения данных, а также не надо приводить тип Serializable к CharacterType после извлечения.
Свойство-расширение обеспечивает явную абстракцию над API Bundle, избавляя вас от необходимости помнить, как хранятся характеристики персонажа и каким ключом надо пользоваться, когда потребуется прочесть или записать characterData.
Теперь используем свойство-расширение в функциях onSaveInstanceState() и onCreate().
private const val CHARACTER_DATA_KEY = "CHARACTER_DATA_KEY" class MainActivity : AppCompatActivity() { private var characterData = CharacterGenerator.generate() override fun onSaveInstanceState(savedInstanceState: Bundle) { super.onSaveInstanceState(savedInstanceState) savedInstanceState.characterData = characterData } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentView(R.layout.activity_main) val binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) characterData = savedInstanceState?.characterData ?: CharacterGenerator.generate() binding.generateButton.setOnClickListener { characterData = CharacterGenerator.generate() displayCharacterData(binding) } displayCharacterData(binding) } . . . . }
Рис.2. Использование нового свойства-расширения (MainActivity.kt)
Снова запустите Samodelkin, пройдя по всем возможностям приложения, поворачивая экран в эмуляторе и нажимая кнопку GENERATE. Вы увидите, что данные персонажа отображаются корректно.
Поздравляем! Вы создали свое первое приложение для Android на Kotlin. Вы узнали о некоторых возможностях, поддерживаемых Kotlin при работе с кодом Java, на котором написан фреймворк Android. И наконец, вы узнали, как возможности Kotlin, такие как расширения и стандартные функции, могут сделать код Android-приложения чище.
В дальнейшем вы познакомитесь с сопрограммами Kotlin - экспериментальной, легковесной и элегантной альтернативой другим моделям выполнения работы в фоновом режиме.
На следующем шаге мы рассмотрим возможности некоторых библиотек.