Compose e outras bibliotecas

Você pode usar suas bibliotecas favoritas no Compose. Nesta seção, descrevemos como incorporar algumas das bibliotecas mais úteis.

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().

class ExampleViewModel : ViewModel() { /*...*/ }

@Composable
fun MyExample(
    viewModel: ExampleViewModel = viewModel()
) {
    // use viewModel here
}

viewModel() retorna um ViewModel já existente ou cria um novo no escopo especificado. O ViewModel será armazenado enquanto o escopo estiver ativo. Por exemplo, se a função que pode ser composta for usada em uma atividade, viewModel() retornará a mesma instância até que a atividade seja concluída ou o processo seja encerrado.

@Composable
fun MyExample(
    // Returns the same instance as long as the activity is alive,
    // just as if you grabbed the instance from an Activity or Fragment
    viewModel: ExampleViewModel = viewModel()
) { /* ... */ }

@Composable
fun MyExample2(
    viewModel: ExampleViewModel = viewModel() // Same instance as in MyExample
) { /* ... */ }

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 de navegação do 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:

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 MyExample(
    viewModel: ExampleViewModel = viewModel()
) {
    val dataExample = viewModel.exampleLiveData.observeAsState()

    // Because the state is read here,
    // MyExample 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.

Recomendamos o uso da biblioteca de navegação Compose para adicionar elementos de navegação aos seus projetos no Compose. Esses elementos permitem que você adicione a IU para navegar entre os elementos que podem ser compostos, enquanto aproveita a infraestrutura e os recursos do componente de navegação.

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 para Android e funciona perfeitamente com o Compose.

A função viewModel() mencionada na seção ViewModel automaticamente usa 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 ExampleViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

@Composable
fun ExampleScreen(
    exampleViewModel: ExampleViewModel = viewModel()
) { /* ... */ }

Hilt e navegação

O Hilt também se integra à biblioteca de navegação do Compose. Adicione as seguintes dependências a mais ao arquivo do Gradle:

app/build.gradle

...
dependencies {
  ...
  implementation 'androidx.hilt:hilt-navigation-compose:1.0.0-alpha02'
}

Se o @HiltViewModel anotado ViewModel estiver com escopo para o gráfico de navegação, use a função que pode ser composta de hiltViewModel que funciona com fragmentos ou atividades que são anotados com @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 exampleViewModel = hiltViewModel<ExampleViewModel>()
            ExampleScreen(exampleViewModel)
        }
        /* ... */
    }
}

Se você precisar recuperar a instância de um ViewModel com escopo para rotas de navegação, transmita a raiz de destino 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 parentViewModel = hiltViewModel<ParentViewModel>(
                    navController.getBackStackEntry("Parent")
                )
                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.

Veja um exemplo das APIs do Compose da biblioteca Paging:

@Composable
fun MyExample(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(lazyPagingItems) {
            Text("Item is $it")
        }
    }
}

Consulte a documentação de listas para ver mais informações sobre como usar a Paging no Compose.

Carregamento de imagem

As bibliotecas Accompanist(link em inglês) apresentam elementos que podem ser compostos fáceis de usar para buscar e exibir imagens de fontes externas, como uma rede. Ela tem integrações com Coil e Glide.

Veja um exemplo de rememberCoilPainter do artefato com.google.accompanist:accompanist-coil:

@Composable
fun MyExample() {
    val painter = rememberCoilPainter("https://picsum.photos/300/300")

    Box {
        Image(
            painter = painter,
            contentDescription = stringResource(R.string.image_content_desc),
        )

        when (painter.loadState) {
            is ImageLoadState.Loading -> {
                // Display a circular progress indicator whilst loading
                CircularProgressIndicator(Modifier.align(Alignment.Center))
            }
            is ImageLoadState.Error -> {
                // If you wish to display some content if the request fails
            }
        }
    }
}