← Назад к вопросам

Как хранятся данные в Activity при изменении конфигурации кроме Bundle

2.0 Middle🔥 121 комментариев
#Android компоненты#Жизненный цикл и навигация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

При изменении конфигурации устройства (поворот экрана, изменение языка, подключение клавиатуры и т.д.) 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 перед убийством процесса.

Практические рекомендации

  1. Используйте ViewModel для данных, связанных с UI логикой
  2. Используйте onSaveInstanceState() только для минимального UI состояния (скролл позиция, временные флаги)
  3. Для постоянных данных используйте базу данных или SharedPreferences
  4. Избегайте статических полей и синглтонов, хранящих ссылки на Context или View
  5. Учитывайте жизненный цикл - разные данные имеют разное время жизни

Современная архитектура Android рекомендует комбинировать эти подходы, например: ViewModel для управления данными + Room для постоянного хранения + SavedStateHandle для восстановления UI состояния.