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(ActivityResultContracts.GetContent()) { uri: Uri? -> imageUri = uri } Column { Button(onClick = { launcher.launch("image/*") }) { Text(text = "Load Image") } Image( painter = rememberAsyncImagePainter(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 UI 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, poderá acessar um ViewModel
em qualquer função que pode ser composta chamando a função viewModel()
. Adicione a seguinte dependência ao arquivo do Gradle:
Groovy
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") }
Em seguida, use a função viewModel()
no seu código.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
retorna um ViewModel
existente ou cria um novo. Por padrão, o ViewModel
retornado tem o escopo definido para a atividade, o fragmento ou o destino de navegação envolvido e é mantido enquanto o escopo estiver ativo.
Por exemplo, se o elemento combinável for usado em uma atividade, viewModel()
vai retornar a mesma instância até que a atividade seja concluída ou o processo seja encerrado.
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 ) { /* ... */ }
Diretrizes de uso
Normalmente, você acessa instâncias ViewModel
em elementos combináveis no nível da tela, ou seja, próximos a um elemento raiz chamado de uma atividade, um fragmento ou um destino de um gráfico de navegação. Isso acontece porque, por padrão, os ViewModel
s são definidos para esses objetos no nível da tela. Leia mais sobre o ciclo de vida e o escopo de um ViewModel
.
Evite transmitir instâncias de ViewModel
para outros elementos combináveis, porque isso pode dificultar o teste desses elementos e quebrar as pré-visualizações. Em vez disso, transmita apenas os dados e as funções de que eles precisam como parâmetros.
Você pode usar instâncias ViewModel
para gerenciar o estado de elementos combináveis no nível da subtela. No entanto, fique atento ao ciclo de vida e escopo do ViewModel
. Se o elemento combinável for independente, considere usar o Hilt para injetar o ViewModel
e evitar a necessidade de transmitir dependências de elementos combináveis principais.
Se o ViewModel
tiver 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.
// 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) } }
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
O componente de navegação oferece suporte a aplicativos do Jetpack Compose. Consulte Como navegar com o Compose e Migrar a navegação do Jetpack para a navegação do Compose para mais informações.
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() { /* ... */ } // import androidx.lifecycle.viewmodel.compose.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.2.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.2.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() { 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) } /* ... */ } }
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() { 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
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.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
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 do Maps Compose para oferecer o Google Maps no seu app. Veja um exemplo de uso:
@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" ) } }
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Efeitos colaterais no Compose
- Estado e Jetpack Compose
- Salvar o estado da interface no Compose