Как получить Context в Jetpack Compose? Проблема с доступом к ресурсам
Правильный способ получения Context в Jetpack Compose
В Jetpack Compose действительно есть встроенный механизм для получения Context — это композиционная локаль LocalContext. Она предоставляет доступ к текущему Context (обычно это Context Activity или Fragment, в котором размещен Composable).
@Composable
fun MyScreen() {
// Получаем Context через LocalContext
val context = LocalContext.current
Button(onClick = {
// Теперь можем использовать context
Toast.makeText(context, "Нажато!", Toast.LENGTH_SHORT).show()
}) {
Text("Нажми меня")
}
}
Важно: LocalContext.current можно вызывать только внутри @Composable функции или лямбды, которая выполняется в контексте композиции. Не пытайтесь использовать его в обычных функциях или блоках инициализации.
Доступ к ресурсам без явного Context
Для работы с ресурсами (строки, цвета, размеры) в Compose есть более удобные способы, которые не требуют прямого доступа к Context:
- Строки: используйте
stringResource(R.string.my_string) - Цвета: используйте
colorResource(R.color.my_color) - Размеры (dimen): используйте
dimensionResource(R.dimen.my_dimen) - Drawable: используйте
painterResource(R.drawable.my_icon)
@Composable
fun ResourceExample() {
val appName = stringResource(R.string.app_name)
val primaryColor = colorResource(R.color.primary)
val icon = painterResource(R.drawable.ic_launcher)
Text(
text = appName,
color = primaryColor
)
Icon(painter = icon, contentDescription = null)
}
Когда нужно передавать Context через параметры?
В некоторых случаях лучше передавать Context как параметр, особенно если ваша функция не является Composable или вы хотите сделать её тестируемой:
// Плохо: скрытая зависимость от Context
class MyRepository {
fun saveData() {
val context = LocalContext.current // Ошибка! Не Composable контекст
}
}
// Хорошо: явная передача Context
class MyRepository(private val context: Context) {
fun saveData() {
// Используем context
}
}
// В Composable передаём Context в конструктор
@Composable
fun MyScreen() {
val context = LocalContext.current
val repository = remember { MyRepository(context) }
}
Важные предостережения
- Не сохраняйте Context в глобальных переменных — это может привести к утечкам памяти. Используйте
rememberили DI-контейнеры. - Для Activity Result API используйте
rememberLauncherForActivityResult— не нужно получать Context. - Для работы с системными сервисами (например, LocationManager) получайте Context через LocalContext и вызывайте
getSystemService()внутри Composable.
В итоге: для большинства задач в Compose вам не нужен Context напрямую — используйте встроенные Resource-функции. Если же Context всё-таки необходим, обращайтесь к LocalContext.current внутри @Composable функции.
Альтернатива: использование CompositionLocalProvider
Если вам нужно заменить Context на другой (например, для тестирования или изоляции), вы можете использовать CompositionLocalProvider:
@Composable
fun CustomContextExample() {
val testContext = MockContext() // ваш тестовый контекст
CompositionLocalProvider(LocalContext provides testContext) {
// Внутри этого блока LocalContext.current вернёт testContext
MyScreen()
}
}
Для доступа к Activity
Если вам нужен именно Activity (например, для запуска Intent), используйте LocalActivity.current (из библиотеки activity-compose):
@Composable
fun MyScreen() {
val activity = LocalActivity.current
Button(onClick = {
activity?.startActivity(Intent(activity, SecondActivity::class.java))
}) {
Text("Открыть другую Activity")
}
}
Этот подход удобен, когда нужно явно указать, какой Context используется в определённой части UI-дерева.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Алгоритмы и структуры данных на Go: полное руководство для начинающих