Вы можете использовать ваши любимые библиотеки в Compose. В этом разделе описывается, как включить несколько самых полезных библиотек.
Активность
Чтобы использовать Compose в действии, необходимо использовать ComponentActivity
, подкласс Activity
, который предоставляет соответствующий LifecycleOwner
и компоненты для Compose. Он также предоставляет дополнительные API, которые отделяют ваш код от переопределения методов в вашем классе активности. Activity Compose предоставляет эти API для компонуемых объектов, так что переопределение методов вне ваших компонуемых объектов или извлечение явного экземпляра Activity
больше не требуется. Более того, эти API гарантируют, что они инициализируются только один раз, выдерживают перекомпозицию и правильно очищаются, если компонуемый объект удаляется из композиции.
Результат действия
API rememberLauncherForActivityResult()
позволяет вам получить результат от действия в вашем компонуемом объекте:
@Composable fun GetContentExample() { var imageUri by remember { mutableStateOf<Uri?>(null) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> imageUri = uri } Column { Button(onClick = { launcher.launch("image/*") }) { Text(text = "Load Image") } Image( painter = rememberAsyncImagePainter(imageUri), contentDescription = "My Image" ) } }
В этом примере демонстрируется простой контракт GetContent()
. Нажатие кнопки запускает запрос. Завершающая лямбда для rememberLauncherForActivityResult()
вызывается, как только пользователь выбирает изображение и возвращается к активности запуска. Это загружает выбранное изображение с помощью функции rememberImagePainter()
Coil.
Любой подкласс ActivityResultContract
может быть использован в качестве первого аргумента rememberLauncherForActivityResult()
. Это означает, что вы можете использовать эту технику для запроса контента из фреймворка и в других распространенных шаблонах. Вы также можете создавать свои собственные контракты и использовать их с этой техникой.
Запрос разрешений на выполнение
Тот же API Activity Result и rememberLauncherForActivityResult()
описанные выше, можно использовать для запроса разрешений времени выполнения с использованием контракта RequestPermission
для одного разрешения или контракта RequestMultiplePermissions
для нескольких разрешений.
Библиотеку разрешений Accompanist можно также использовать на уровне выше этих API для сопоставления текущего предоставленного состояния разрешений с состоянием, которое может использовать ваш пользовательский интерфейс Compose.
Обработка системной кнопки «Назад»
Чтобы обеспечить настраиваемую навигацию назад и переопределить поведение системной кнопки «Назад» по умолчанию из вашего компонуемого объекта, ваш компонуемый объект может использовать BackHandler
для перехвата этого события:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Первый аргумент контролирует, включен ли BackHandler
в данный момент; вы можете использовать этот аргумент для временного отключения обработчика на основе состояния вашего компонента. Завершающая лямбда будет вызвана, если пользователь активирует системное событие возврата, а BackHandler
в данный момент включен.
ViewModel
Если вы используете библиотеку Architecture Components ViewModel , вы можете получить доступ к ViewModel
из любого компонуемого объекта, вызвав функцию viewModel()
. Добавьте следующую зависимость в ваш файл Gradle:
Круто
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5' }
Котлин
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") }
Затем вы можете использовать функцию viewModel()
в своем коде.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
возвращает существующую ViewModel
или создает новую. По умолчанию возвращаемая ViewModel
ограничена включающей активностью, фрагментом или навигационным назначением и сохраняется до тех пор, пока область жива.
Например, если составной объект используется в действии, viewModel()
возвращает тот же экземпляр до тех пор, пока действие не будет завершено или процесс не будет завершен.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( // Returns the same instance as long as the activity is alive, // just as if you grabbed the instance from an Activity or Fragment viewModel: MyViewModel = viewModel() ) { /* ... */ } @Composable fun MyScreen2( viewModel: MyViewModel = viewModel() // Same instance as in MyScreen ) { /* ... */ }
Руководство по использованию
Обычно вы получаете доступ к экземплярам ViewModel
на уровне компонуемых объектов экрана , то есть близко к корневому компонуемому объекту, вызываемому из действия, фрагмента или назначения графа навигации. Это связано с тем, что ViewModel
по умолчанию ограничены этими объектами уровня экрана . Подробнее о жизненном цикле и области действия ViewModel
читайте здесь .
Постарайтесь избегать передачи экземпляров ViewModel
другим компонуемым объектам, так как это может затруднить тестирование этих компонуемых объектов и может нарушить предварительные просмотры . Вместо этого передавайте в качестве параметров только необходимые данные и функции.
Вы можете использовать экземпляры ViewModel
для управления состоянием для компонуемых объектов на уровне подэкрана , однако помните о жизненном цикле и области действия ViewModel
. Если компонуемый объект является самодостаточным, вы можете рассмотреть возможность использования Hilt для внедрения ViewModel
, чтобы избежать необходимости передавать зависимости от родительских компонуемых объектов.
Если у вашего ViewModel
есть зависимости, viewModel()
принимает необязательный ViewModelProvider.Factory
в качестве параметра.
Дополнительную информацию о ViewModel
в Compose и о том, как экземпляры используются с библиотекой Navigation Compose, а также о действиях и фрагментах, см. в документации по взаимодействию .
Потоки данных
Compose поставляется с расширениями для самых популярных потоковых решений Android. Каждое из этих расширений предоставляется различным артефактом:
-
LiveData.observeAsState()
включен в артефактandroidx.compose.runtime:runtime-livedata:$composeVersion
. -
Flow.collectAsState()
не требует дополнительных зависимостей. -
Observable.subscribeAsState()
включен в артефактandroidx.compose.runtime:runtime-rxjava2:$composeVersion
илиandroidx.compose.runtime:runtime-rxjava3:$composeVersion
.
Эти артефакты регистрируются как слушатель и представляют значения как State
. Всякий раз, когда выдается новое значение, Compose перекомпоновывает те части пользовательского интерфейса, где используется это state.value
. Например, в этом коде ShowData
перекомпоновывает каждый раз, когда exampleLiveData
выдает новое значение.
// import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { val dataExample = viewModel.exampleLiveData.observeAsState() // Because the state is read here, // MyScreen recomposes whenever dataExample changes. dataExample.value?.let { ShowData(dataExample) } }
Асинхронные операции в Compose
Jetpack Compose позволяет выполнять асинхронные операции с использованием сопрограмм из ваших компонуемых объектов.
Дополнительную информацию см. в описании API LaunchedEffect
, produceState
и rememberCoroutineScope
в документации по побочным эффектам .
Навигация
Компонент Navigation обеспечивает поддержку приложений Jetpack Compose. Для получения дополнительной информации см. Navigating with Compose и Migrate Jetpack Navigation to Navigation Compose.
Эфес
Hilt — рекомендуемое решение для внедрения зависимостей в приложения Android, которое прекрасно работает с Compose.
Функция viewModel()
упомянутая в разделе ViewModel, автоматически использует ViewModel, который Hilt конструирует с помощью аннотации @HiltViewModel
. Мы предоставили документацию с информацией об интеграции ViewModel в Hilt .
@HiltViewModel class MyViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private val repository: ExampleRepository ) : ViewModel() { /* ... */ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { /* ... */ }
Рукоять и навигация
Hilt также интегрируется с библиотекой Navigation Compose. Добавьте следующие дополнительные зависимости в ваш файл Gradle:
Круто
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' }
Котлин
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.2.0") }
При использовании Navigation Compose всегда используйте составную функцию hiltViewModel
для получения экземпляра вашего @HiltViewModel
аннотированного ViewModel
. Это работает с фрагментами или действиями, которые аннотированы @AndroidEntryPoint
.
Например, если ExampleScreen
является пунктом назначения в навигационном графике, вызовите hiltViewModel()
чтобы получить экземпляр ExampleViewModel
, ограниченный пунктом назначения, как показано во фрагменте кода ниже:
// import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" NavHost(navController, startDestination = startRoute) { composable("example") { backStackEntry -> // Creates a ViewModel from the current BackStackEntry // Available in the androidx.hilt:hilt-navigation-compose artifact val viewModel = hiltViewModel<MyViewModel>() MyScreen(viewModel) } /* ... */ } }
Если вам необходимо получить экземпляр ViewModel
, ограниченный навигационными маршрутами или навигационным графиком , используйте составную функцию hiltViewModel
и передайте соответствующий backStackEntry
в качестве параметра:
// import androidx.hilt.navigation.compose.hiltViewModel // import androidx.navigation.compose.getBackStackEntry @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" val innerStartRoute = "exampleWithRoute" NavHost(navController, startDestination = startRoute) { navigation(startDestination = innerStartRoute, route = "Parent") { // ... composable("exampleWithRoute") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("Parent") } val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry) ExampleWithRouteScreen(parentViewModel) } } } }
Пейджинг
Библиотека Paging упрощает постепенную загрузку данных и поддерживается в Compose. Страница релиза Paging содержит информацию о дополнительной зависимости paging-compose
, которую необходимо добавить в проект и его версию.
Вот пример API Compose библиотеки Paging:
@Composable fun MyScreen(flow: Flow<PagingData<String>>) { val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
Дополнительную информацию об использовании разбиения на страницы в Compose можно найти в документации по спискам и сеткам .
Карты
Вы можете использовать библиотеку Maps Compose для предоставления Google Maps в вашем приложении. Вот пример использования:
@Composable fun MapsExample() { val singapore = LatLng(1.35, 103.87) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(singapore, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Marker( state = remember { MarkerState(position = singapore) }, title = "Singapore", snippet = "Marker in Singapore" ) } }
Рекомендовано для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Побочные эффекты в Compose
- State и Jetpack Compose
- Сохранение состояния пользовательского интерфейса в Compose
Вы можете использовать ваши любимые библиотеки в Compose. В этом разделе описывается, как включить несколько самых полезных библиотек.
Активность
Чтобы использовать Compose в действии, необходимо использовать ComponentActivity
, подкласс Activity
, который предоставляет соответствующий LifecycleOwner
и компоненты для Compose. Он также предоставляет дополнительные API, которые отделяют ваш код от переопределения методов в вашем классе активности. Activity Compose предоставляет эти API для компонуемых объектов, так что переопределение методов вне ваших компонуемых объектов или извлечение явного экземпляра Activity
больше не требуется. Более того, эти API гарантируют, что они инициализируются только один раз, выдерживают перекомпозицию и правильно очищаются, если компонуемый объект удаляется из композиции.
Результат действия
API rememberLauncherForActivityResult()
позволяет вам получить результат от действия в вашем компонуемом объекте:
@Composable fun GetContentExample() { var imageUri by remember { mutableStateOf<Uri?>(null) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> imageUri = uri } Column { Button(onClick = { launcher.launch("image/*") }) { Text(text = "Load Image") } Image( painter = rememberAsyncImagePainter(imageUri), contentDescription = "My Image" ) } }
В этом примере демонстрируется простой контракт GetContent()
. Нажатие кнопки запускает запрос. Завершающая лямбда для rememberLauncherForActivityResult()
вызывается, как только пользователь выбирает изображение и возвращается к активности запуска. Это загружает выбранное изображение с помощью функции rememberImagePainter()
Coil.
Любой подкласс ActivityResultContract
может быть использован в качестве первого аргумента rememberLauncherForActivityResult()
. Это означает, что вы можете использовать эту технику для запроса контента из фреймворка и в других распространенных шаблонах. Вы также можете создавать свои собственные контракты и использовать их с этой техникой.
Запрос разрешений на выполнение
Тот же API Activity Result и rememberLauncherForActivityResult()
описанные выше, можно использовать для запроса разрешений времени выполнения с использованием контракта RequestPermission
для одного разрешения или контракта RequestMultiplePermissions
для нескольких разрешений.
Библиотеку разрешений Accompanist можно также использовать на уровне выше этих API для сопоставления текущего предоставленного состояния разрешений с состоянием, которое может использовать ваш пользовательский интерфейс Compose.
Обработка системной кнопки «Назад»
Чтобы обеспечить настраиваемую навигацию назад и переопределить поведение системной кнопки «Назад» по умолчанию из вашего компонуемого объекта, ваш компонуемый объект может использовать BackHandler
для перехвата этого события:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Первый аргумент контролирует, включен ли BackHandler
в данный момент; вы можете использовать этот аргумент для временного отключения обработчика на основе состояния вашего компонента. Завершающая лямбда будет вызвана, если пользователь активирует системное событие возврата, а BackHandler
в данный момент включен.
ViewModel
Если вы используете библиотеку Architecture Components ViewModel , вы можете получить доступ к ViewModel
из любого компонуемого объекта, вызвав функцию viewModel()
. Добавьте следующую зависимость в ваш файл Gradle:
Круто
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5' }
Котлин
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") }
Затем вы можете использовать функцию viewModel()
в своем коде.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
возвращает существующую ViewModel
или создает новую. По умолчанию возвращаемая ViewModel
ограничена включающей активностью, фрагментом или навигационным назначением и сохраняется до тех пор, пока область жива.
Например, если составной объект используется в действии, viewModel()
возвращает тот же экземпляр до тех пор, пока действие не будет завершено или процесс не будет завершен.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( // Returns the same instance as long as the activity is alive, // just as if you grabbed the instance from an Activity or Fragment viewModel: MyViewModel = viewModel() ) { /* ... */ } @Composable fun MyScreen2( viewModel: MyViewModel = viewModel() // Same instance as in MyScreen ) { /* ... */ }
Руководство по использованию
Обычно вы получаете доступ к экземплярам ViewModel
на уровне компонуемых объектов экрана , то есть близко к корневому компонуемому объекту, вызываемому из действия, фрагмента или назначения графа навигации. Это связано с тем, что ViewModel
по умолчанию ограничены этими объектами уровня экрана . Подробнее о жизненном цикле и области действия ViewModel
читайте здесь .
Постарайтесь избегать передачи экземпляров ViewModel
другим компонуемым объектам, так как это может затруднить тестирование этих компонуемых объектов и может нарушить предварительные просмотры . Вместо этого передавайте в качестве параметров только необходимые данные и функции.
Вы можете использовать экземпляры ViewModel
для управления состоянием для компонуемых объектов на уровне подэкрана , однако помните о жизненном цикле и области действия ViewModel
. Если компонуемый объект является самодостаточным, вы можете рассмотреть возможность использования Hilt для внедрения ViewModel
, чтобы избежать необходимости передавать зависимости от родительских компонуемых объектов.
Если у вашего ViewModel
есть зависимости, viewModel()
принимает необязательный ViewModelProvider.Factory
в качестве параметра.
Дополнительную информацию о ViewModel
в Compose и о том, как экземпляры используются с библиотекой Navigation Compose, а также о действиях и фрагментах, см. в документации по взаимодействию .
Потоки данных
Compose поставляется с расширениями для самых популярных потоковых решений Android. Каждое из этих расширений предоставляется различным артефактом:
-
LiveData.observeAsState()
включен в артефактandroidx.compose.runtime:runtime-livedata:$composeVersion
. -
Flow.collectAsState()
не требует дополнительных зависимостей. -
Observable.subscribeAsState()
включен в артефактandroidx.compose.runtime:runtime-rxjava2:$composeVersion
илиandroidx.compose.runtime:runtime-rxjava3:$composeVersion
.
Эти артефакты регистрируются как слушатель и представляют значения как State
. Всякий раз, когда выдается новое значение, Compose перекомпоновывает те части пользовательского интерфейса, где используется это state.value
. Например, в этом коде ShowData
перекомпоновывает каждый раз, когда exampleLiveData
выдает новое значение.
// import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { val dataExample = viewModel.exampleLiveData.observeAsState() // Because the state is read here, // MyScreen recomposes whenever dataExample changes. dataExample.value?.let { ShowData(dataExample) } }
Асинхронные операции в Compose
Jetpack Compose позволяет выполнять асинхронные операции с использованием сопрограмм из ваших компонуемых объектов.
Дополнительную информацию см. в описании API LaunchedEffect
, produceState
и rememberCoroutineScope
в документации по побочным эффектам .
Навигация
Компонент Navigation обеспечивает поддержку приложений Jetpack Compose. Для получения дополнительной информации см. Navigating with Compose и Migrate Jetpack Navigation to Navigation Compose.
Эфес
Hilt — рекомендуемое решение для внедрения зависимостей в приложения Android, которое прекрасно работает с Compose.
Функция viewModel()
упомянутая в разделе ViewModel, автоматически использует ViewModel, который Hilt конструирует с помощью аннотации @HiltViewModel
. Мы предоставили документацию с информацией об интеграции ViewModel в Hilt .
@HiltViewModel class MyViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private val repository: ExampleRepository ) : ViewModel() { /* ... */ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { /* ... */ }
Рукоять и навигация
Hilt также интегрируется с библиотекой Navigation Compose. Добавьте следующие дополнительные зависимости в ваш файл Gradle:
Круто
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' }
Котлин
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.2.0") }
При использовании Navigation Compose всегда используйте составную функцию hiltViewModel
для получения экземпляра вашего @HiltViewModel
аннотированного ViewModel
. Это работает с фрагментами или действиями, которые аннотированы @AndroidEntryPoint
.
Например, если ExampleScreen
является пунктом назначения в навигационном графике, вызовите hiltViewModel()
чтобы получить экземпляр ExampleViewModel
, ограниченный пунктом назначения, как показано во фрагменте кода ниже:
// import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" NavHost(navController, startDestination = startRoute) { composable("example") { backStackEntry -> // Creates a ViewModel from the current BackStackEntry // Available in the androidx.hilt:hilt-navigation-compose artifact val viewModel = hiltViewModel<MyViewModel>() MyScreen(viewModel) } /* ... */ } }
Если вам необходимо получить экземпляр ViewModel
, ограниченный навигационными маршрутами или навигационным графиком , используйте составную функцию hiltViewModel
и передайте соответствующий backStackEntry
в качестве параметра:
// import androidx.hilt.navigation.compose.hiltViewModel // import androidx.navigation.compose.getBackStackEntry @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" val innerStartRoute = "exampleWithRoute" NavHost(navController, startDestination = startRoute) { navigation(startDestination = innerStartRoute, route = "Parent") { // ... composable("exampleWithRoute") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("Parent") } val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry) ExampleWithRouteScreen(parentViewModel) } } } }
Пейджинг
Библиотека Paging упрощает постепенную загрузку данных и поддерживается в Compose. Страница релиза Paging содержит информацию о дополнительной зависимости paging-compose
, которую необходимо добавить в проект и его версию.
Вот пример API Compose библиотеки Paging:
@Composable fun MyScreen(flow: Flow<PagingData<String>>) { val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
Дополнительную информацию об использовании разбиения на страницы в Compose можно найти в документации по спискам и сеткам .
Карты
Вы можете использовать библиотеку Maps Compose для предоставления Google Maps в вашем приложении. Вот пример использования:
@Composable fun MapsExample() { val singapore = LatLng(1.35, 103.87) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(singapore, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Marker( state = remember { MarkerState(position = singapore) }, title = "Singapore", snippet = "Marker in Singapore" ) } }
Рекомендовано для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Побочные эффекты в Compose
- State и Jetpack Compose
- Сохранение состояния пользовательского интерфейса в Compose