Compose dan library lainnya

Anda dapat menggunakan library favorit dalam Compose. Bagian ini menjelaskan cara menggabungkan beberapa library yang paling berguna.

Aktivitas

Untuk dapat menggunakan Compose dalam aktivitas, Anda harus menggunakan ComponentActivity, subclass Activity yang menyediakan LifecycleOwner dan komponen yang sesuai untuk Compose. Class ini juga menyediakan API tambahan yang memisahkan kode dari penggantian metode di class aktivitas. Activity Compose mengekspos API ini ke composable sehingga penggantian metode di luar composable atau pengambilan instance Activity eksplisit tidak diperlukan lagi. Selain itu, API ini juga memastikan API tersebut hanya diinisialisasi satu kali, tidak terpengaruh rekomposisi, dan membersihkan dengan sempurna jika composable dihapus dari komposisi.

Hasil Aktivitas

API rememberLauncherForActivityResult() memungkinkan Anda mendapatkan hasil dari aktivitas dalam composable Anda:

@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"
        )
    }
}

Contoh ini menunjukkan kontrak GetContent() yang sederhana. Mengetuk tombol akan meluncurkan permintaan. Lambda akhir untuk rememberLauncherForActivityResult() dipanggil setelah pengguna memilih gambar dan kembali ke aktivitas peluncuran. Tindakan ini akan memuat gambar yang dipilih menggunakan fungsi rememberImagePainter() Coil.

Setiap subclass ActivityResultContract dapat digunakan sebagai argumen pertama untuk rememberLauncherForActivityResult(). Artinya, Anda dapat menggunakan teknik ini untuk meminta konten dari framework dan dalam pola umum lainnya. Anda juga dapat membuat kontrak kustom versi Anda sendiri dan menggunakannya dengan teknik ini.

Meminta Izin Runtime

Activity Result API yang sama dan rememberLauncherForActivityResult() yang dijelaskan di atas dapat digunakan untuk meminta izin runtime menggunakan kontrak RequestPermission untuk satu izin atau kontrak RequestMultiplePermissions untuk beberapa izin.

Library Izin Accompanist juga dapat digunakan sebagai lapisan di atas API tersebut untuk memetakan status izin yang diberikan saat ini ke dalam Status yang dapat digunakan UI Compose Anda.

Menangani tombol kembali sistem

Untuk menyediakan navigasi kembali kustom dan mengganti perilaku default tombol kembali sistem dari dalam composable, composable Anda dapat menggunakan BackHandler untuk menangkap peristiwa tersebut:

var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
   // Handle back press
}

Argumen pertama mengontrol apakah BackHandler saat ini diaktifkan atau tidak; Anda dapat menggunakan argumen ini untuk sementara waktu menonaktifkan pengendali berdasarkan status komponen Anda. Lambda akhir akan dipanggil jika pengguna memicu peristiwa kembali sistem, dan BackHandler saat ini diaktifkan.

ViewModel

Jika Anda menggunakan library ViewModel Komponen Arsitektur, Anda dapat mengakses ViewModel dari composable mana pun dengan memanggil fungsi viewModel().

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

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

viewModel() menampilkan ViewModel yang sudah ada atau membuat yang baru dalam cakupan yang ditentukan. ViewModel dipertahankan selama cakupan masih aktif. Misalnya, jika komposisi digunakan dalam suatu aktivitas, viewModel() akan menampilkan instance yang sama sampai aktivitas itu selesai atau prosesnya diakhiri.

@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
) { /* ... */ }

Jika ViewModel Anda memiliki dependensi, viewModel() akan menggunakan ViewModelProvider.Factory opsional sebagai parameter.

Untuk mengetahui informasi selengkapnya tentang ViewModel di Compose dan bagaimana instance digunakan dengan library Navigasi Compose, atau aktivitas dan fragmen, lihat dokumen Interoperabilitas.

Aliran data

Compose dilengkapi dengan ekstensi untuk solusi berbasis aliran data yang paling populer dari Android. Setiap ekstensi ini disediakan oleh artefak yang berbeda:

Artefak ini terdaftar sebagai pemroses dan mewakili nilai sebagai State. Setiap kali nilai baru dikeluarkan, Compose merekomposisi bagian-bagian UI tempat state.value digunakan. Misalnya, dalam kode ini, ShowData merekomposisi setiap kali exampleLiveData mengeluarkan nilai baru.

@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)
    }
}

Operasi asinkron di Compose

Jetpack Compose memungkinkan Anda menjalankan operasi asinkron menggunakan coroutine dari dalam composable.

Lihat LaunchedEffect, produceState, dan rememberCoroutineScope API di dokumentasi efek samping untuk mengetahui informasi selengkapnya.

Sebaiknya gunakan library navigasi Compose untuk menambahkan elemen navigasi ke project Compose Anda. Elemen ini memungkinkan Anda menambahkan UI untuk bernavigasi di antara composable sekaligus memanfaatkan infrastruktur dan fitur komponen Navigasi.

Pelajari lebih lanjut integrasi ini dalam dokumentasi Menavigasi dengan Compose.

Hilt

Hilt adalah solusi yang direkomendasikan untuk menerapkan injeksi dependensi di aplikasi Android, dan berfungsi lancar dengan Compose.

Fungsi viewModel() yang disebutkan di bagian ViewModel secara otomatis menggunakan ViewModel yang dibuat oleh Hilt dengan anotasi @HiltViewModel. Kami telah menyediakan dokumentasi dengan informasi tentang integrasi ViewModel Hilt.

@HiltViewModel
class ExampleViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

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

Hilt dan Navigasi

Hilt juga terintegrasi dengan library navigasi Compose. Tambahkan dependensi tambahan berikut ke file Gradle Anda:

app/build.gradle

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

Jika @HiltViewModel yang dianotasi dengan ViewModel disertakan ke grafik navigasi, gunakan fungsi yang dapat dikomposisi hiltViewModel yang berfungsi dengan fragmen atau aktivitas yang dianotasi dengan @AndroidEntryPoint.

Misalnya, jika ExampleScreen adalah tujuan dalam grafik navigasi, panggil hiltViewModel() untuk mendapatkan instance ExampleViewModel yang disertakan ke tujuan sebagaimana ditunjukkan dalam cuplikan kode di bawah:

// 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)
        }
        /* ... */
    }
}

Jika Anda perlu mengambil instance ViewModel yang disertakan ke rute navigasi, teruskan root tujuan sebagai parameter:

// 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 {
                  navController.getBackStackEntry("Parent")
                }
                val parentViewModel = hiltViewModel<ParentViewModel>(
                  parentEntry
                )
                ExampleWithRouteScreen(parentViewModel)
            }
        }
    }
}

Paging

Library Paging mempermudah Anda memuat data secara bertahap dan didukung di Compose. Halaman rilis Paging berisi informasi tentang dependensi paging-compose tambahan yang perlu ditambahkan pada project dan versinya.

Berikut adalah contoh Compose API dari library Paging:

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

Lihat dokumentasi Daftar untuk mengetahui informasi selengkapnya tentang penggunaan Paging di Compose.

Gambar sedang dimuat

Library Coil dari Instacart menawarkan fungsi yang dapat dikomposisi untuk memuat gambar dari sumber eksternal, seperti memuat gambar jarak jauh melalui jaringan.

Berikut adalah contoh rememberImagePainter dari artefak io.coil-kt:coil-compose:

@Composable
fun MyExample() {
    val painter = rememberImagePainter(
        data = "https://picsum.photos/300/300",
        builder = {
            crossfade(true)
        }
    )

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

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