Você pode usar suas bibliotecas favoritas no Compose. Nesta seção, descrevemos como incorporar algumas das bibliotecas mais úteis.
Atividade
Para usar o Compose em uma atividade, use a
ComponentActivity
,
uma subclasse de Activity
que fornece o LifecycleOwner
e os
componentes adequados para o Compose. Ela fornece também outras APIs que separam o código
da substituição de métodos na sua classe de atividade.
O Activity Compose
expõe essas APIs a elementos que podem ser compostos, de modo que a substituição de métodos fora desses
elementos ou a recuperação de uma instância Activity
explícita não seja mais necessária.
Além disso, as APIs garantem que elas sejam inicializadas apenas uma vez, sobrevivam
à recomposição e sejam apagadas adequadamente quando o elemento combinável é removido da
composição.
Resultado da atividade
A
API rememberLauncherForActivityResult()
permite que você
receba o resultado de uma atividade
no elemento combinável:
@Composable
fun GetContentExample() {
var imageUri by remember { mutableStateOf<Uri?>(null) }
val launcher = rememberLauncherForActivityResult(GetContent()) { uri: Uri? ->
imageUri = uri
}
Column {
Button(onClick = { launcher.launch("image/*") }) {
Text(text = "Load Image")
}
Image(
painter = rememberImagePainter(imageUri),
contentDescription = "My Image"
)
}
}
O exemplo demonstra um contrato
GetContent()
simples. A solicitação será iniciada quando você tocar no botão. O lambda final de
rememberLauncherForActivityResult()
será invocado quando o usuário selecionar uma imagem e retornar à atividade de inicialização.
Essa ação carrega a imagem selecionada usando a função rememberImagePainter()
da Coil.
Qualquer subclasse de
ActivityResultContract
pode ser usada como primeiro argumento de
rememberLauncherForActivityResult()
.
Ou seja, é possível usar essa técnica para solicitar conteúdo do framework
e em outros padrões comuns. Com essa técnica, também é possível
criar e usar seus próprios
contratos personalizados.
Como solicitar permissões de execução
A mesma API Activity Result e
rememberLauncherForActivityResult()
explicadas acima podem ser usadas para
solicitar permissões de execução
usando o
contrato RequestPermission
para uma única permissão ou o
contrato RequestMultiplePermissions
para várias permissões.
A biblioteca Accompanist Permissions também pode ser usada em uma camada acima dessas APIs para mapear o estado concedido atual de permissões no estado que sua IU do Compose pode usar.
Como processar o botão "Voltar" do sistema
Para fornecer uma navegação de retorno personalizada
e substituir o comportamento padrão do botão "Voltar" do sistema no
elemento combinável, o elemento pode usar um
BackHandler
para interceptar o evento:
var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
// Handle back press
}
O primeiro argumento controla se o
BackHandler
está ativado. Você pode usá-lo para desativar temporariamente o processador
com base no estado do componente. O lambda final será invocado se o
usuário acionar um evento de retorno do sistema enquanto o
BackHandler
estiver ativado.
ViewModel
Se você usar a biblioteca Architecture Components
ViewModel, vai poder acessar um
ViewModel
em qualquer elemento combinável
chamando a
função
viewModel()
.
class MyViewModel : ViewModel() { /*...*/ }
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
// use viewModel here
}
A viewModel()
retorna um ViewModel
já existente ou cria um novo no escopo
especificado. O ViewModel
será mantido enquanto o escopo estiver ativo. Por exemplo,
se o elemento combinável for usado em uma atividade, a função viewModel()
vai retornar a mesma
instância até que a atividade seja concluída ou o processo seja encerrado.
@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
) { /* ... */ }
Caso seu ViewModel tenha dependências, viewModel()
usará um
ViewModelProvider.Factory
opcional como parâmetro.
Para ver mais informações sobre ViewModel
no Compose e sobre como as instâncias são usadas
com a biblioteca Navigation Compose ou sobre atividades e fragmentos,
consulte os documentos sobre interoperabilidade.
Streams de dados
O Compose vem com extensões para as soluções mais populares com base em stream do Android. Cada uma dessas extensões é fornecida por um artefato diferente:
LiveData.observeAsState()
incluído no artefatoandroidx.compose.runtime:runtime-livedata:$composeVersion
.Flow.collectAsState()
não requer dependências extras.Observable.subscribeAsState()
incluído no artefatoandroidx.compose.runtime:runtime-rxjava2:$composeVersion
ouandroidx.compose.runtime:runtime-rxjava3:$composeVersion
.
Esses artefatos são registrados como listeners e representam os valores como
State
. Sempre que um novo valor
é emitido, o Compose faz a recomposição das partes da IU em que state.value
é
usado. Por exemplo, neste código, ShowData
faz a recomposição todas as vezes que
exampleLiveData
emite um novo valor.
@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)
}
}
Operações assíncronas no Compose
O Jetpack Compose permite executar operações assíncronas usando corrotinas em funções que podem ser compostas.
Consulte as APIs LaunchedEffect
, produceState
e rememberCoroutineScope
na
documentação de efeitos colaterais para mais
informações.
Navegação
Recomendamos o uso da biblioteca Navigation Compose para adicionar elementos de navegação aos seus projetos do Compose. Esses elementos permitem que você adicione a IU para navegar entre os elementos combináveis enquanto aproveita a infraestrutura e os recursos do componente Navigation.
Para saber mais sobre essa integração, consulte a documentação Como navegar com o Compose.
Hilt
O Hilt é a solução recomendada para injeção de dependência em apps Android e funciona perfeitamente com o Compose.
A função viewModel()
mencionada na seção ViewModel
usa automaticamente o ViewModel criado pelo Hilt com a
anotação @HiltViewModel
. Disponibilizamos uma documentação com informações sobre a integração do
ViewModel do Hilt.
@HiltViewModel
class MyViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle,
private val repository: ExampleRepository
) : ViewModel() { /* ... */ }
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) { /* ... */ }
Hilt e navegação
O Hilt também se integra à biblioteca Navigation Compose. Adicione as seguintes dependências a mais ao arquivo do Gradle:
Groovy
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.0.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.0.0") }
Ao usar a biblioteca Navigation Compose, sempre use a função de composição hiltViewModel
para acessar uma instância do ViewModel
anotado com @HiltViewModel
.
Isso funciona com fragmentos ou atividades que incluem a anotação
@AndroidEntryPoint
.
Por exemplo, se ExampleScreen
for um destino em um gráfico de navegação,
chame hiltViewModel()
para ter uma instância de ExampleViewModel
com escopo
para o destino, como mostrado no snippet de código abaixo:
// import androidx.hilt.navigation.compose.hiltViewModel
@Composable
fun MyApp() {
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)
}
/* ... */
}
}
Se você precisar recuperar a instância de um ViewModel
com escopo para
rotas de navegação ou o
gráfico de navegação, use a função de composição hiltViewModel
e transmita a backStackEntry
correspondente como um parâmetro:
// import androidx.hilt.navigation.compose.hiltViewModel
// import androidx.navigation.compose.getBackStackEntry
@Composable
fun MyApp() {
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
A biblioteca
Paging
facilita o carregamento gradual de dados e é compatível com o Compose.
A página de lançamento
da Paging contém
informações sobre a dependência complementar paging-compose
, que precisa ser adicionada
ao projeto e à respectiva versão.
Confira um exemplo das APIs do Compose da biblioteca Paging:
@Composable
fun MyScreen(flow: Flow<PagingData<String>>) {
val lazyPagingItems = flow.collectAsLazyPagingItems()
LazyColumn {
items(lazyPagingItems) {
Text("Item is $it")
}
}
}
Consulte a documentação sobre listas e grades para mais informações sobre como usar a Paging no Compose.
Maps
Você pode usar a biblioteca Maps Compose para oferecer o Google Maps no seu app. Veja um exemplo de uso:
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"
)
}