Como adicionar o Jetpack Compose ao app

Caso queira usar o Jetpack Compose em um projeto já existente, defina seu projeto com as configurações e dependências necessárias.

Configurar seu ambiente de desenvolvimento

Instalar a versão correta do Android Studio

Para ter a melhor experiência de desenvolvimento com o Jetpack Compose, faça o download do Android Studio Arctic Fox e configure o Plug-in do Android para Gradle correspondente à versão do Android Studio:

buildscript {
    ...
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        ...
    }
}

Configurar o Kotlin

Confira se você está usando o Kotlin 1.5.31 no projeto:

plugins {
    id 'org.jetbrains.kotlin:android' version '1.5.31'
}

Configurar o Gradle

Você precisa definir o nível mínimo da API do seu app como 21 ou mais recente e ativar o Jetpack Compose no arquivo build.gradle do app, como mostrado abaixo. Defina também a versão do plug-in do compilador Kotlin.

android {
    defaultConfig {
        ...
        minSdkVersion 21
    }

    buildFeatures {
        // Enables Jetpack Compose for this module
        compose true
    }
    ...

    // Set both the Java and Kotlin compilers to target Java 8.
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }

    composeOptions {
        kotlinCompilerExtensionVersion '1.0.5'
    }
}

Adicionar dependências do toolkit do Jetpack Compose

Inclua dependências do toolkit do Jetpack Compose no arquivo build.gradle do app, como mostrado abaixo.

dependencies {
    // Integration with activities
    implementation 'androidx.activity:activity-compose:1.3.1'
    // Compose Material Design
    implementation 'androidx.compose.material:material:1.0.5'
    // Animations
    implementation 'androidx.compose.animation:animation:1.0.5'
    // Tooling support (Previews, etc.)
    implementation 'androidx.compose.ui:ui-tooling:1.0.5'
    // Integration with ViewModels
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
    // UI Tests
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.5'
}

Reutilizar o tema de visualização no Compose

Se você acabou de adicionar o Compose ao seu projeto, talvez queira que ele herde os temas disponíveis no sistema de visualização, em vez de reescrever seu próprio tema do Material Design no Compose desde o início.

Se estiver usando a biblioteca MDC no seu app Android, a biblioteca MDC Compose Theme Adapter permitirá que você reutilize facilmente nas suas funções compostas os temas de cor, tipografia e forma presentes nos temas baseados na visualização existentes. Isso é possível com a API MdcTheme.

Se você estiver usando temas XML do AppCompat, use o AppCompat Compose Theme Adapter, que contém a API AppCompatTheme.

Inclua a dependência necessária no arquivo build.gradle do app, conforme mostrado abaixo:

dependencies {
    // When using a MDC theme
    implementation "com.google.android.material:compose-theme-adapter:1.0.5"

    // When using a AppCompat theme
    implementation "com.google.accompanist:accompanist-appcompat-theme:0.16.0"
}

Começar a migrar para o Compose

Imagine que queremos migrar o texto de saudação do usuário para o Jetpack Compose no nosso aplicativo. Podemos ter o seguinte conteúdo em um layout XML:

<...>
    <!-- Other content -->

    <TextView
        android:id="@+id/greeting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/margin_small"
        android:layout_marginEnd="@dimen/margin_small"
        android:gravity="center_horizontal"
        android:text="@string/greeting"
        android:textAppearance="?attr/textAppearanceHeadline5"
        ... />
</...>

Para migrá-lo para o Compose, podemos substituir a View por uma ComposeView, mantendo os mesmos parâmetros de layout e id:

<...>
    <!-- Other content -->

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/greeting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</...>

Em seguida, na Activity ou no Fragment que usam esse layout XML, conseguimos a ComposeView e chamamos o método setContent para adicionar conteúdo do Compose a ele:

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...

        val greeting = findViewById<ComposeView>(R.id.greeting)
        greeting.setContent {
            MdcTheme { // or AppCompatTheme
                Greeting()
            }
        }
    }
}

@Composable
private fun Greeting() {
    Text(
        text = stringResource(R.string.greeting),
        style = MaterialTheme.typography.h5,
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = dimensionResource(R.dimen.margin_small))
            .wrapContentWidth(Alignment.CenterHorizontally)
    )
}

Para mais informações sobre a ComposeView e outras APIs de interoperabilidade, consulte o Guia das APIs de interoperabilidade. Para saber mais sobre stringResource, dimensionResource e outras APIs de recursos no Compose, confira o guia Recursos no Compose.

Testar a IU híbrida

Após migrar partes do seu app para o Compose, os testes são essenciais para garantir que não haja nenhuma falha.

Quando uma atividade ou um fragmento usa o Compose, em vez de usar a ActivityScenarioRule, você precisa usar a createAndroidComposeRule, que integra a ActivityScenarioRule com uma ComposeTestRule que possibilita testar o código do Compose e da visualização ao mesmo tempo.

class MyActivityTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test
    fun testGreeting() {
        val greeting = InstrumentationRegistry.getInstrumentation()
            .targetContext.resources.getString(R.string.greeting)

        composeTestRule.onNodeWithText(greeting).assertIsDisplayed()
    }
}

Consulte o guia Como testar o layout do Compose para saber mais sobre testes e a interoperabilidade com o Espresso.

Compose na sua arquitetura

O Compose é compatível com a maioria das arquiteturas de apps e oferece integrações com muitas outras bibliotecas conhecidas. Portanto, não é necessário mudar outras camadas da hierarquia se você quiser começar a usar o Compose no seu app.

O snippet de código a seguir mostra como o Compose funciona com os ViewModels de componentes da arquitetura usando a função viewModel() e como faz a coleta de um fluxo do Kotlin usando collectAsState().

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyScreen()
        }
    }
}

@Composable
private fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsState()
    when {
        uiState.isLoading -> { /* ... */ }
        uiState.isSuccess -> { /* ... */ }
        uiState.isError -> { /* ... */ }
    }
}

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(MyScreenState.Loading)
    val uiState: StateFlow<MyScreenState> = _uiState
}

Para ver mais integrações, como carregamento de imagem, Paging ou Hilt, confira o guia do Compose e de outras bibliotecas.

Se você usa o componente de navegação no app, confira a seção "Interoperabilidade" do guia "Como navegar com o Compose".

Próximas etapas

Veja mais informações sobre o Compose no índice de documentação. Há diferentes abordagens para adotar o Compose no app. Saiba mais sobre isso no guia Como adotar o Compose no seu app, que também tem links para outros guias, como o Como integrar o Compose à arquitetura de app que você já usa e Como integrar o Compose à IU já existente.