В Compose можно использовать любимые библиотеки. В этом разделе рассказывается, как добавить некоторые из наиболее полезных библиотек.
Действия
Чтобы использовать Compose в действии, необходимо применить ComponentActivity – подкласс Activity, который предоставляет Compose подходящие LifecycleOwner и компоненты. Кроме того, в нем есть дополнительные API, которые позволяют отделить код от переопределяемых методов в классе действий.
Activity Compose
предоставляет эти API для композиций, поэтому вам больше не нужно переопределять методы вне композиций или получать явный экземпляр Activity.
Кроме того, эти API гарантируют, что инициализация выполняется только один раз, что они сохраняются при повторной композиции и что они корректно очищаются, если компонуемый объект удаляется из композиции.
Результат действия
rememberLauncherForActivityResult() API позволяет получать результат из действия в вашей composable-функции:
@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 результатов действий и 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 из любой composable-функции, вызвав функцию viewModel(). Добавьте в файл Gradle следующую зависимость:
Яркий
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0") }
После этого вы сможете использовать функцию viewModel() в своем коде.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel() возвращает существующий объект ViewModel или создает новый. По умолчанию возвращаемый объект ViewModel относится к текущему действию, фрагменту или пункту назначения навигации и сохраняется, пока существует область действия.
Например, если composable-функция используется в действии, 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 осуществляется на уровне экрана, то есть рядом с корневым компонентом, вызываемым из действия, фрагмента или пункта назначения графа навигации. Это связано с тем, что по умолчанию ViewModels
относятся к объектам на уровне экрана. Подробнее
ViewModel
о жизненном цикле и области действия…
Старайтесь не передавать экземпляры ViewModel другим композициям, так как это может затруднить тестирование и нарушить работу предварительного просмотра. Вместо этого передавайте только необходимые данные и функции в качестве параметров.
Вы можете использовать экземпляры ViewModel для управления состоянием композиций на уровне дочернего экрана, но учитывайте ViewModel жизненный цикл и область действия. Если компонент composable является автономным, вы можете использовать Hilt, чтобы внедрить ViewModel и избежать передачи зависимостей от родительских компонентов composable.
Если у вашего свойства 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. Подробнее о том, как использовать навигацию с Compose и как перенести навигацию Jetpack в Compose…
Hilt
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 и навигация
Hilt также интегрируется с библиотекой Navigation Compose. Добавьте в файл Gradle следующие дополнительные зависимости:
Яркий
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.4.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.4.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, относящийся к маршрутам навигации или графу навигации, используйте composable-функцию 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 библиотеки Paging для 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 = remember { MarkerState(position = singapore) }, title = "Singapore", snippet = "Marker in Singapore" ) } }
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Побочные эффекты в Compose
- Состояние и Jetpack Compose
- Сохранение состояния интерфейса в Compose