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(ActivityResultContracts.GetContent()) { uri: Uri? ->
        imageUri = uri
    }
    Column {
        Button(onClick = { launcher.launch("image/*") }) {
            Text(text = "Load Image")
        }
        Image(
            painter = rememberAsyncImagePainter(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 libraryViewModel Komponen Arsitektur, Anda dapat mengakses ViewModel dari composable mana pun dengan memanggil fungsi viewModel(). Tambahkan dependensi berikut ke file Gradle Anda:

Groovy

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5")
}

Kemudian, Anda dapat menggunakan fungsi viewModel() dalam kode Anda.

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

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    // use viewModel here
}

viewModel() menampilkan ViewModel yang sudah ada atau membuat yang baru. Secara default, ViewModel yang ditampilkan dicakup ke aktivitas, fragmen, atau tujuan navigasi yang melingkupi, dan dipertahankan selama cakupan masih aktif.

Misalnya, jika composable digunakan dalam suatu aktivitas, viewModel() akan menampilkan instance yang sama sampai aktivitas itu selesai atau prosesnya diakhiri.

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

Panduan penggunaan

Anda biasanya mengakses instance ViewModel pada composable tingkat layar, yaitu, dekat dengan composable root yang dipanggil dari aktivitas, fragmen, atau tujuan grafik Navigasi. Hal ini karena ViewModel, secara default, dicakup untuk objek tingkat layar tersebut. Baca selengkapnya tentang siklus proses dan cakupan ViewModel di sini.

Cobalah untuk menghindari penerusan instance ViewModel ke composable lain karena hal ini dapat membuat composable tersebut lebih sulit diuji dan dapat merusak pratinjau. Sebagai gantinya, hanya teruskan data dan fungsi yang diperlukan sebagai parameter.

Anda dapat menggunakan instance ViewModel untuk mengelola status untuk composable sub-level layar, tetapi perhatikan siklus proses dan cakupan ViewModel. Jika composable bersifat mandiri, sebaiknya pertimbangkan untuk menggunakan Hilt untuk memasukkan ViewModel agar tidak perlu meneruskan dependensi dari composable induk.

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 Compose Navigasi, 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.

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

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.

Komponen Navigasi memberikan dukungan untuk aplikasi Jetpack Compose. Lihat Menavigasi dengan Compose dan Memigrasikan Navigasi Jetpack ke Navigation Compose untuk mengetahui informasi selengkapnya.

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 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 dan Navigasi

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

Groovy

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

Kotlin

dependencies {
    implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
}

Saat menggunakan Compose Navigasi, selalu gunakan fungsi composable hiltViewModel untuk mendapatkan instance ViewModel yang dianotasi @HiltViewModel. Ini 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() {
    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)
        }
        /* ... */
    }
}

Jika Anda perlu mengambil instance ViewModel yang disertakan ke rute navigasi atau grafik navigasi sebagai gantinya, gunakan hiltViewModel fungsi composable dan teruskan backStackEntry yang sesuai sebagai parameter:

// 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

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

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

Maps

Anda dapat menggunakan library Compose Maps untuk menyediakan Google Maps di aplikasi Anda. Berikut adalah contoh penggunaannya:

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