Вы можете использовать свои любимые библиотеки в Compose. В этом разделе описывается, как включить несколько наиболее полезных библиотек.
Действия
Чтобы использовать Compose в действии, необходимо использовать ComponentActivity – подкласс Activity, который предоставляет Compose соответствующие компоненты и LifecycleOwner. Кроме того, в нем есть дополнительные API, которые позволяют не переопределять методы в классе действия.
Activity Compose предоставляет эти API для composable-функций, поэтому вам больше не нужно переопределять методы за пределами composable-функций или получать явный экземпляр Activity.
Кроме того, эти API гарантируют, что они инициализируются только один раз, выдерживают рекомпозицию и правильно очищаются, если composable-функция удаляется из композиции.
Результат действия
API rememberLauncherForActivityResult() позволяет получить результат действия в 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.
В качестве первого аргумента для rememberLauncherForActivityResult() можно использовать любой подкласс ActivityResultContract.
Это означает, что вы можете использовать этот метод для запроса контента из фреймворка
и в других распространенных шаблонах. Вы также можете создавать собственные специальные контракты и использовать их с этим методом.
Запрос динамических разрешений
Тот же Activity Result API и rememberLauncherForActivityResult(), описанные выше, можно использовать для запроса динамических разрешений с помощью контракта RequestPermission для одного разрешения или контракта RequestMultiplePermissions для нескольких разрешений.
Библиотеку Accompanist Permissions также можно использовать в качестве уровня над этими API, чтобы сопоставить текущее состояние предоставленных разрешений с состоянием, которое может использовать ваш интерфейс Compose.
Как обрабатывать нажатие системной кнопки "Назад"
Чтобы настроить обратную навигацию и переопределить режим работы по умолчанию для системной кнопки "Назад" в composable-функции, используйте 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 осуществляется на уровне экрана, то есть рядом с корневой composable-функцией, вызываемой из Activity, фрагмента или пункта назначения графа Navigation. Это связано с тем, что ViewModel по умолчанию относятся к объектам на уровне экрана. Подробнее
ViewModel
о жизненном цикле и области действия…
Старайтесь не передавать экземпляры ViewModel в другие composable-функции, так как это может усложнить их тестирование и нарушить работу предварительного просмотра. Вместо этого передавайте только данные
и функции, которые им нужны в качестве параметров.
Вы можете использовать экземпляры ViewModel для управления состоянием composable-функций на уровне подэкрана, но учитывайте жизненный цикл и область действия 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 позволяет выполнять асинхронные операции с помощью сопрограмм из composable-функций.
Дополнительную информацию об API LaunchedEffect, produceState и rememberCoroutineScope можно найти в документации по побочным эффектам.
Навигация
Компонент Navigation поддерживает приложения Jetpack Compose. Дополнительную информацию можно найти в статьях Навигация с помощью Compose и Перенос Jetpack Navigation в Navigation Compose.
Hilt
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
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 всегда используйте composable-функцию 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, ограниченный маршрутами навигации или графом навигации, используйте 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 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") } } }
Дополнительную информацию об использовании Paging в Compose можно найти в документации по спискам и сеткам.
Карты
Чтобы добавить Google Карты в приложение, можно использовать библиотеку Maps Compose. Вот пример ее применения:
@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