Приведи пример утечки Context
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример утечки Context в Android
Утечка Context — частая проблема в разработке под Android, когда Activity, Service или Application контекст удерживается в памяти дольше необходимого, препятствуя сборке мусора. Это может привести к утечкам памяти, OutOfMemoryError и некорректной работе приложения. Основная причина — неправильное хранение контекста в статических полях или долгоживущих объектах (например, в синглтонах или фоновых потоках), которые переживают жизненный цикл компонента.
Конкретный пример утечки
Рассмотрим типичный случай: создание синглтона (например, менеджера данных), который хранит ссылку на Context для доступа к ресурсам или системным сервисам. Если передать в него контекст Activity, а не Application, это приведёт к утечке.
// НЕПРАВИЛЬНО: синглтон с утечкой Context
class DataManager private constructor(context: Context) {
private val appContext: Context = context.applicationContext
private val sharedPreferences: SharedPreferences
init {
// Хранение контекста, переданного из Activity
sharedPreferences = context.getSharedPreferences("app_data", Context.MODE_PRIVATE)
}
companion object {
private var instance: DataManager? = null
fun getInstance(context: Context): DataManager {
if (instance == null) {
instance = DataManager(context) // Передаётся контекст Activity
}
return instance!!
}
}
fun saveData(key: String, value: String) {
sharedPreferences.edit().putString(key, value).apply()
}
}
При вызове DataManager.getInstance(this) из Activity синглтон сохранит ссылку на её контекст. Поскольку синглтон живёт всё время работы приложения, Activity не сможет быть уничтожена сборщиком мусора даже после закрытия (например, при повороте экрана). Это классическая утечка, которую можно обнаружить через Android Profiler или LeakCanary.
Как исправить утечку
- Использование Application Context: Для синглтонов всегда передавайте контекст приложения, доступный через
context.applicationContext. Он не привязан к жизненному циклу UI-компонентов. - Использование WeakReference: Если нужен контекст Activity (например, для диалогов), применяйте
WeakReference, но с осторожностью. - Очистка ссылок: В
onDestroy()Activity удаляйте ссылки на контекст в сторонних объектах.
Исправленный код:
// ПРАВИЛЬНО: безопасный синглтон
class SafeDataManager private constructor(context: Context) {
private val appContext: Context = context.applicationContext // Используем Application Context
private val sharedPreferences: SharedPreferences
init {
sharedPreferences = appContext.getSharedPreferences("app_data", Context.MODE_PRIVATE)
}
companion object {
@Volatile
private var instance: SafeDataManager? = null
fun getInstance(context: Context): SafeDataManager {
return instance ?: synchronized(this) {
instance ?: SafeDataManager(context).also { instance = it }
}
}
}
}
Ключевые моменты:
- Application Context безопасен для долгоживущих операций (доступ к ресурсам, SharedPreferences).
- Activity Context используйте только для задач, связанных с UI (показ диалогов, привязка к жизненному циклу).
- Всегда проверяйте, не храните ли вы контекст в статических полях, фоновых потоках или колбэках (например, в Listeners или Callbacks), которые не отписываются вовремя.
Профилактика утечек
- LeakCanary: Интегрируйте библиотеку для автоматического обнаружения утечек.
- Android Profiler: Анализируйте память в реальном времени.
- Правила:
- Избегайте нестатических вложенных классов в Activity (они хранят ссылку на внешний класс).
- Для Handler используйте
WeakReferenceилиviewModelScopeв архитектуре MVVM. - Отписывайтесь от BroadcastReceiver, EventBus в
onDestroy().
Утечки Context снижают производительность и стабильность приложения, поэтому важно применять паттерны безопасной работы с памятью с самого начала разработки.