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

Какие знаешь проблемы, если заменить все ApplicationContext на ActivityContext и наоборот?

1.7 Middle🔥 111 комментариев
#Android компоненты#JVM и память

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

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

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

Проблемы замены ApplicationContext на ActivityContext и наоборот

Замена контекстов без учёта их семантики и жизненного цикла приводит к серьёзным проблемам в Android-приложениях. Контексты — это не взаимозаменяемые сущности, и каждая из них предназначена для конкретных сценариев.

🔥 Проблемы при замене ApplicationContext на ActivityContext

  1. Утечки памяти (Memory Leaks)

    // Проблемный код: ActivityContext переживает Activity
    class MySingleton(context: Context) {
        // Сохраняем ссылку на Activity
        private val activityContext: Context = context
        
        companion object {
            private var instance: MySingleton? = null
            
            fun getInstance(context: Context): MySingleton {
                if (instance == null) {
                    // Если передали ActivityContext, он будет удерживать Activity
                    instance = MySingleton(context)
                }
                return instance!!
            }
        }
    }
    

    ActivityContext содержит ссылки на Activity и её View-иерархию. Если такой контекст сохраняется в объектах с большим временем жизни (синглтоны, репозитории), это препятствует сборке мусора для Activity.

  2. Некорректная тематизация (Theming)

    // ApplicationContext не содержит тему Activity
    val dialog = AlertDialog.Builder(applicationContext) // Не будет применена тема Activity
        .setTitle("Title")
        .create()
    
  3. Ошибки при работе с LayoutInflater

    // Разные результаты с разными контекстами
    val inflater1 = LayoutInflater.from(activityContext) // Правильно применяет тему
    val inflater2 = LayoutInflater.from(applicationContext) // Тема по умолчанию
    
  4. Проблемы с поиском ресурсов ActivityContext может иметь доступ к ресурсам, специфичным для текущей конфигурации (ориентация, локализация), которые недоступны через ApplicationContext.

🔥 Проблемы при замене ActivityContext на ApplicationContext

  1. Краши при работе с UI

    // Вызовет WindowManager$BadTokenException
    val dialog = Dialog(applicationContext) // Требуется ActivityContext
    dialog.show()
    
    // Аналогичная проблема
    val toast = Toast(applicationContext) // На некоторых версиях Android
    toast.show()
    
  2. Отсутствие привязки к жизненному циклу Activity

    // BroadcastReceiver не будет автоматически отписываться
    class MyActivity : AppCompatActivity() {
        private val receiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                // Обработка
            }
        }
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // Правильно: ActivityContext, отписка при onDestroy
            registerReceiver(receiver, IntentFilter("ACTION"))
            
            // Опасно: ApplicationContext, нужно ручное управление
            applicationContext.registerReceiver(receiver, IntentFilter("ACTION"))
        }
    }
    
  3. Проблемы с разрешениями (Runtime Permissions)

    // Не работает с ApplicationContext
    if (ContextCompat.checkSelfPermission(applicationContext, permission) 
        != PackageManager.PERMISSION_GRANTED) {
        // Запрос разрешений требует ActivityContext
        ActivityCompat.requestPermissions(applicationContext, ...) // Ошибка компиляции
    }
    
  4. Ограничения при запуске Activity

    val intent = Intent(applicationContext, NextActivity::class.java)
    // Требует FLAG_ACTIVITY_NEW_TASK, иначе краш
    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
    applicationContext.startActivity(intent)
    

📋 Рекомендации по выбору контекста

Используйте ApplicationContext когда:

  • Работаете с синглтонами и долгоживущими объектами
  • Регистрируете глобальные BroadcastReceiver
  • Обращаетесь к системным сервисам (getSystemService() для сервисов вроде LAYOUT_INFLATER_SERVICE, POWER_SERVICE)
  • Работаете с базой данных, файлами, SharedPreferences

Используйте ActivityContext когда:

  • Создаёте UI-компоненты (Dialog, Toast, Snackbar)
  • Инфлейтите layout'ы с применением темы
  • Запускаете Activity (без флага FLAG_ACTIVITY_NEW_TASK)
  • Работаете с FragmentManager
  • Запрашиваете runtime-разрешения

🎯 Лучшие практики

// Правильный подход: внедрение подходящего контекста
class MyRepository(
    private val appContext: Context, // ApplicationContext
    private val resources: Resources
) {
    fun loadData() {
        // Используем appContext для долгоживущих операций
    }
}

// В Activity/Fragment
class MyFragment : Fragment() {
    private lateinit var repository: MyRepository
    
    override fun onAttach(context: Context) {
        super.onAttach(context)
        repository = MyRepository(
            context.applicationContext, // Безопасный контекст
            resources
        )
    }
    
    private fun showDialog() {
        // Используем ActivityContext для UI
        val dialog = Dialog(requireContext())
        dialog.show()
    }
}

Ключевое правило: Всегда используйте самый узко-специфичный контекст, который выполняет задачу. Если можно использовать ApplicationContext — используйте его, так как он безопаснее. Если задача требует ActivityContext (работа с UI, диалоги, запуск Activity) — передавайте именно его, но следите за временем жизни.

Какие знаешь проблемы, если заменить все ApplicationContext на ActivityContext и наоборот? | PrepBro