Вы можете использовать свои любимые библиотеки в 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 Result Activity и rememberLauncherForActivityResult()
, описанные выше, можно использовать для запроса разрешений во время выполнения с использованием контракта RequestPermission
для одного разрешения или контракта RequestMultiplePermissions
для нескольких разрешений.
Библиотеку разрешений аккомпаниатора также можно использовать на уровне выше этих API для сопоставления текущего предоставленного состояния разрешений с состоянием, которое может использовать ваш пользовательский интерфейс Compose.
Обработка кнопки возврата системы
Чтобы обеспечить настраиваемую обратную навигацию и переопределить поведение системной кнопки «Назад» по умолчанию из вашего составного объекта, ваш составной объект может использовать BackHandler
для перехвата этого события:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Первый аргумент определяет, включен ли BackHandler
в данный момент; вы можете использовать этот аргумент, чтобы временно отключить обработчик в зависимости от состояния вашего компонента. Завершающая лямбда-выражение будет вызвана, если пользователь инициирует системное обратное событие, а BackHandler
в данный момент включен.
ViewModel
Если вы используете библиотеку ViewModel компонентов архитектуры , вы можете получить доступ к ViewModel
из любого компонуемого объекта, вызвав функцию viewModel()
. Добавьте следующую зависимость в ваш файл Gradle:
классный
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1' }
Котлин
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1") }
Затем вы можете использовать функцию 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
в документации по побочным эффектам .
Навигация
Компонент навигации обеспечивает поддержку приложений Jetpack Compose. Дополнительные сведения см. в разделе «Навигация с помощью Compose» и «Миграция навигации Jetpack Navigation в Navigation Compose» .
Рукоять
Hilt — рекомендуемое решение для внедрения зависимостей в приложениях Android, которое прекрасно работает с Compose.
Функция viewModel()
, упомянутая в разделе ViewModel, автоматически использует ViewModel, которую Hilt конструирует с аннотацией @HiltViewModel
. Мы предоставили документацию с информацией об интеграции Hilt ViewModel .
@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.0.0' }
Котлин
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.0.0") }
При использовании Navigation Compose всегда используйте составную функцию hiltViewModel
, чтобы получить экземпляр вашего ViewModel
с аннотацией @HiltViewModel
. Это работает с фрагментами или действиями, которые помечены @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) } } } }
Пейджинг
Библиотека подкачки упрощает постепенную загрузку данных и поддерживается в Compose. Страница выпуска Paging содержит информацию о дополнительной зависимости paging-compose
, которую необходимо добавить в проект, и его версии.
Вот пример API Compose библиотеки подкачки:
@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 в свое приложение. Вот пример использования:
@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 = MarkerState(position = singapore), title = "Singapore", snippet = "Marker in Singapore" ) } }
Рекомендуется для вас
- Примечание. Текст ссылки отображается, когда JavaScript отключен.
- Побочные эффекты в Compose
- State и Jetpack Compose
- Сохранение состояния пользовательского интерфейса в Compose