Как хранятся данные в Activity при изменении конфигурации кроме Bundle
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
При изменении конфигурации устройства (поворот экрана, изменение языка, подключение клавиатуры и т.д.) Activity уничтожается и создается заново. Помимо стандартного механизма с Bundle через методы onSaveInstanceState() и onRestoreInstanceState(), существуют и другие подходы для сохранения данных, которые я разделю на несколько категорий.
Архитектурные решения и компоненты Android
1. ViewModel (библиотека Android Architecture Components/Lifecycle)
Это основной современный способ сохранения данных, не связанных с UI, при изменении конфигурации. ViewModel переживает пересоздание Activity, так как хранится в ViewModelStore, которым управляет компонент жизненного цикла (например, Activity).
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> get() = _data
fun loadData() {
_data.value = "Сохраненные данные"
}
}
class MyActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
viewModel.data.observe(this) { data ->
// Обновление UI с сохраненными данными
}
}
}
Важно: ViewModel НЕ переживает полное уничтожение процесса (например, при нехватке памяти), поэтому для постоянного хранения нужны другие механизмы.
2. Сохранение в onRetainNonConfigurationInstance() (устаревший способ)
Этот метод позволял сохранять произвольные объекты при изменении конфигурации, но сейчас считается устаревшим в пользу ViewModel.
// Устаревший подход (для понимания)
public class MyActivity extends Activity {
private MyDataObject data;
@Override
public Object onRetainNonConfigurationInstance() {
return data; // Возвращаем объект для новой Activity
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
data = (MyDataObject) getLastNonConfigurationInstance();
}
}
Постоянное хранилище
3. Сохранение в SharedPreferences
Для простых данных (настройки, флаги, небольшие значения):
// Сохранение
val prefs = getSharedPreferences("my_prefs", MODE_PRIVATE)
prefs.edit().putString("key", "value").apply()
// Восстановление
val restoredValue = prefs.getString("key", "default")
4. Локальная база данных (Room, SQLite)
Для структурированных данных, которые должны сохраняться между сессиями:
@Entity
data class User(
@PrimaryKey val id: Int,
val name: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Insert
fun insert(user: User)
}
5. Сохранение в файловой системе
Для больших данных, бинарных файлов, кэша:
// Внутреннее хранилище
val file = File(filesDir, "data.txt")
file.writeText("сохраненные данные")
// Внешнее хранилище (требует разрешений)
val externalFile = File(getExternalFilesDir(null), "data.txt")
6. Content Providers
Для предоставления доступа к данным другим приложениям или для работы с системными данными.
Специальные механизмы
7. Fragment с setRetainInstance(true)
Fragment может сохранять свое состояние при изменении конфигурации:
class MyRetainedFragment : Fragment() {
private var data: MyData? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true // Fragment не будет пересоздан
}
}
Важно: Этот подход устарел с появлением ViewModel и может создавать проблемы с управлением памятью.
8. Статические поля (НЕ РЕКОМЕНДУЕТСЯ)
Технически возможно, но это антипаттерн из-за утечек памяти:
object DataHolder {
var data: String? = null // Может вызвать утечку Activity!
}
9. Сохранение в Application классе
Для глобальных данных, которые нужны во всем приложении:
class MyApplication : Application() {
val appData = mutableMapOf<String, Any>()
}
Сравнение подходов
| Механизм | Переживает смену конфигурации | Переживает убийство процесса | Рекомендация |
|---|---|---|---|
| ViewModel | ✅ Да | ❌ Нет | ✅ Основной подход |
| Bundle | ✅ Да | ✅ Да* | ✅ Для UI состояния |
| SharedPreferences | ✅ Да | ✅ Да | ✅ Для настроек |
| База данных | ✅ Да | ✅ Да | ✅ Для структурированных данных |
| Статические поля | ✅ Да | ❌ Нет | ❌ Избегать |
*Только если система успеет сохранить Bundle перед убийством процесса.
Практические рекомендации
- Используйте ViewModel для данных, связанных с UI логикой
- Используйте onSaveInstanceState() только для минимального UI состояния (скролл позиция, временные флаги)
- Для постоянных данных используйте базу данных или SharedPreferences
- Избегайте статических полей и синглтонов, хранящих ссылки на Context или View
- Учитывайте жизненный цикл - разные данные имеют разное время жизни
Современная архитектура Android рекомендует комбинировать эти подходы, например: ViewModel для управления данными + Room для постоянного хранения + SavedStateHandle для восстановления UI состояния.