คุณใช้ไลบรารีที่ชื่นชอบใน Compose ได้ ส่วนนี้จะอธิบายวิธีรวมไลบรารีที่มีประโยชน์ที่สุดบางส่วนเข้าด้วยกัน
กิจกรรม
หากต้องการใช้ Compose ในกิจกรรม คุณต้องใช้ ComponentActivity ซึ่งเป็นคลาสย่อยของ Activity ที่มี LifecycleOwner และคอมโพเนนต์ที่เหมาะสมสำหรับ Compose นอกจากนี้ยังมี API เพิ่มเติมที่แยกโค้ดของคุณออกจากการลบล้างเมธอดในคลาสกิจกรรม
Activity Compose จะแสดง API เหล่านี้ต่อ Composable เพื่อให้ไม่จำเป็นต้องลบล้างเมธอดนอก Composable หรือดึงข้อมูลอินสแตนซ์ Activity ที่ชัดเจนอีกต่อไป
นอกจากนี้ API เหล่านี้ยังช่วยให้มั่นใจว่ามีการเริ่มต้นเพียงครั้งเดียว คงอยู่หลังจากการจัดองค์ประกอบใหม่ และล้างข้อมูลอย่างเหมาะสมหากมีการนำ Composable ออกจากองค์ประกอบ
ผลลัพธ์ของกิจกรรม
API rememberLauncherForActivityResult() ช่วยให้คุณรับผลลัพธ์จากกิจกรรมใน Composable ได้ ดังนี้
@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" ) } }
ตัวอย่างนี้แสดงสัญญา GetContent() แบบง่าย การแตะปุ่มจะเป็นการเปิดคำขอ ระบบจะเรียกใช้ Lambda ต่อท้ายสำหรับ rememberLauncherForActivityResult() เมื่อผู้ใช้เลือกรูปภาพและกลับไปที่กิจกรรมการเปิดตัว
ซึ่งจะโหลดรูปภาพที่เลือกโดยใช้ฟังก์ชัน rememberImagePainter() ของ Coil
คลาสย่อยใดๆ ของ ActivityResultContract สามารถใช้เป็นอาร์กิวเมนต์แรกของ rememberLauncherForActivityResult() ได้
ซึ่งหมายความว่าคุณสามารถใช้เทคนิคนี้เพื่อขอเนื้อหาจากเฟรมเวิร์กและในรูปแบบทั่วไปอื่นๆ ได้ นอกจากนี้ คุณยังสร้างสัญญาที่กำหนดเองและใช้กับเทคนิคนี้ได้ด้วย
การขอสิทธิ์รันไทม์
คุณสามารถใช้ Activity Result API และ rememberLauncherForActivityResult() เดียวกันกับที่อธิบายไว้ข้างต้นเพื่อขอสิทธิ์รันไทม์โดยใช้สัญญา RequestPermission สำหรับสิทธิ์เดียวหรือสัญญา RequestMultiplePermissions สำหรับสิทธิ์หลายรายการ
นอกจากนี้ คุณยังใช้ไลบรารีสิทธิ์ Accompanist เป็นเลเยอร์เหนือ API เหล่านั้นเพื่อแมปสถานะที่ได้รับสิทธิ์ในปัจจุบันกับสถานะที่ Compose UI ของคุณใช้ได้
การจัดการปุ่มย้อนกลับของระบบ
หากต้องการใช้การนำทางย้อนกลับที่กำหนดเองและลบล้างลักษณะการทำงานเริ่มต้นของปุ่มย้อนกลับของระบบจากภายใน Composable ของคุณ Composable จะใช้ BackHandler เพื่อสกัดกั้นเหตุการณ์นั้นได้
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
อาร์กิวเมนต์แรกจะควบคุมว่า BackHandler เปิดใช้อยู่หรือไม่ คุณสามารถใช้อาร์กิวเมนต์นี้เพื่อปิดใช้แฮนเดิลชั่วคราวตามสถานะของคอมโพเนนต์ ระบบจะเรียกใช้ Lambda ต่อท้ายหากผู้ใช้ทริกเกอร์เหตุการณ์ย้อนกลับของระบบ และ BackHandler เปิดใช้อยู่ในปัจจุบัน
ViewModel
หากใช้ไลบรารี Architecture Components ViewModel คุณจะเข้าถึง ViewModel ได้จาก Composable ใดก็ได้โดยเรียกใช้ฟังก์ชัน viewModel() เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในไฟล์ Gradle
ดึงดูด
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0") }
จากนั้นคุณจะใช้ฟังก์ชัน viewModel() ในโค้ดได้
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel() จะแสดงผล ViewModel ที่มีอยู่หรือสร้างใหม่ โดยค่าเริ่มต้น ViewModel ที่แสดงผลจะกำหนดขอบเขตเป็นกิจกรรมที่ล้อมรอบ, Fragment หรือปลายทางการนำทาง และจะเก็บไว้ตราบใดที่ขอบเขตยังคงอยู่
ตัวอย่างเช่น หากใช้ Composable ในกิจกรรม viewModel() จะแสดงผลอินสแตนซ์เดียวกันจนกว่ากิจกรรมจะเสร็จสิ้นหรือกระบวนการถูกหยุด
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 ) { /* ... */ }
หลักเกณฑ์การใช้งาน
โดยปกติแล้ว คุณจะเข้าถึงอินสแตนซ์ ViewModel ที่ Composable ระดับหน้าจอ ซึ่งอยู่ใกล้กับ Composable รูทที่เรียกจากกิจกรรม, Fragment หรือปลายทางของกราฟการนําทาง เนื่องจากโดยค่าเริ่มต้น ViewModel จะกำหนดขอบเขตไว้ที่ออบเจ็กต์ระดับหน้าจอเหล่านั้น อ่านเพิ่มเติมเกี่ยวกับวงจรและขอบเขตของ ViewModel ที่นี่
พยายามหลีกเลี่ยงการส่งอินสแตนซ์ ViewModel ไปยัง Composable อื่นๆ เนื่องจากอาจทำให้ Composable เหล่านั้นทดสอบได้ยากขึ้นและอาจทำให้เวอร์ชันตัวอย่างใช้งานไม่ได้ แต่ให้ส่งเฉพาะข้อมูลและฟังก์ชันที่จำเป็นเป็นพารามิเตอร์แทน
คุณสามารถใช้อินสแตนซ์ ViewModel เพื่อจัดการสถานะสำหรับ Composable ระดับหน้าจอย่อยได้ แต่โปรดคำนึงถึงวงจรและขอบเขตของ ViewModel ด้วย หาก Composable มีความสมบูรณ์ในตัว คุณอาจต้องพิจารณาใช้ Hilt เพื่อแทรก ViewModel เพื่อหลีกเลี่ยงการส่งผ่านทรัพยากร Dependency จาก Composable ระดับบนสุด
หาก ViewModel มีการขึ้นต่อกัน viewModel() จะใช้ ViewModelProvider.Factory ที่ไม่บังคับเป็นพารามิเตอร์
ดูข้อมูลเพิ่มเติมเกี่ยวกับ ViewModel ใน Compose และวิธีใช้อินสแตนซ์กับไลบรารี Navigation Compose หรือกิจกรรมและ Fragment ได้ที่เอกสารความสามารถในการทำงานร่วมกัน
สตรีมข้อมูล
Compose มาพร้อมกับส่วนขยายสำหรับโซลูชันแบบสตรีมที่ได้รับความนิยมมากที่สุดของ Android ส่วนขยายแต่ละรายการเหล่านี้มาจากอาร์ติแฟกต์ที่แตกต่างกัน ดังนี้
LiveData.observeAsState()รวมอยู่ในอาร์ติแฟกต์androidx.compose.runtime:runtime-livedata:$composeVersionFlow.collectAsState()ไม่จำเป็นต้องใช้ทรัพยากร Dependency เพิ่มเติมObservable.subscribeAsState()รวมอยู่ในอาร์ติแฟกต์androidx.compose.runtime:runtime-rxjava2:$composeVersionหรือandroidx.compose.runtime:runtime-rxjava3:$composeVersion
อาร์ติแฟกต์เหล่านี้จะลงทะเบียนเป็น Listener และแสดงค่าเป็น State เมื่อใดก็ตามที่มีการปล่อยค่าใหม่ Compose จะจัดองค์ประกอบส่วนต่างๆ ของ UI ที่ใช้ state.value นั้นอีกครั้ง ตัวอย่างเช่น ในโค้ดนี้ ShowData จะจัดองค์ประกอบใหม่ทุกครั้งที่ exampleLiveData แสดงค่าใหม่
// 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) } }
การดำเนินการแบบอะซิงโครนัสใน Compose
Jetpack Compose ช่วยให้คุณดำเนินการแบบอะซิงโครนัสโดยใช้โครูทีนจากภายใน Composable ได้
ดูข้อมูลเพิ่มเติมเกี่ยวกับ API LaunchedEffect, produceState และ rememberCoroutineScope ในเอกสารประกอบเกี่ยวกับผลข้างเคียง
การนำทาง
คอมโพเนนต์การนำทางรองรับแอปพลิเคชัน Jetpack Compose ดูข้อมูลเพิ่มเติมได้ที่การนำทางด้วย Compose และย้ายข้อมูล Jetpack Navigation ไปยัง Navigation Compose
Hilt
Hilt เป็นโซลูชันที่แนะนำสำหรับการแทรก Dependency ในแอป Android และทำงานร่วมกับ Compose ได้อย่างราบรื่น
ฟังก์ชัน viewModel() ที่กล่าวถึงในส่วน ViewModel จะใช้ ViewModel ที่ Hilt สร้างขึ้นด้วยคำอธิบายประกอบ @HiltViewModel โดยอัตโนมัติ เราได้จัดทำเอกสารประกอบที่มีข้อมูลเกี่ยวกับการผสานรวม 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 และการนำทาง
นอกจากนี้ Hilt ยังผสานรวมกับไลบรารี Navigation Compose ด้วย เพิ่มทรัพยากร Dependency เพิ่มเติมต่อไปนี้ลงในไฟล์ Gradle
ดึงดูด
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.4.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.4.0") }
เมื่อใช้ Navigation Compose ให้ใช้ฟังก์ชันที่ประกอบกันได้ hiltViewModel เสมอเพื่อรับอินสแตนซ์ของ ViewModel ที่มีคำอธิบายประกอบ @HiltViewModel
ซึ่งใช้ได้กับ Fragment หรือกิจกรรมที่มีคำอธิบายประกอบเป็น @AndroidEntryPoint
ตัวอย่างเช่น หาก ExampleScreen เป็นปลายทางในกราฟการนำทาง ให้เรียกใช้ hiltViewModel() เพื่อรับอินสแตนซ์ของ ExampleViewModel ที่กำหนดขอบเขตไปยังปลายทางดังที่แสดงในข้อมูลโค้ดด้านล่าง
// 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) } /* ... */ } }
หากต้องการเรียกข้อมูลอินสแตนซ์ของ ViewModel ที่กำหนดขอบเขตเป็นเส้นทางการนำทางหรือกราฟการนำทางแทน ให้ใช้ฟังก์ชันที่ประกอบกันได้ hiltViewModel และส่ง backStackEntry ที่เกี่ยวข้องเป็นพารามิเตอร์ ดังนี้
// 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) } } } }
เพจจิ้ง
ไลบรารีเพจจิ้งช่วยให้คุณโหลดข้อมูลทีละน้อยได้ง่ายขึ้นและรองรับใน Compose
หน้ารุ่นของ Paging มีข้อมูลเกี่ยวกับการขึ้นต่อกันของ paging-compose เพิ่มเติมที่ต้องเพิ่มลงในโปรเจ็กต์และเวอร์ชันของโปรเจ็กต์
ตัวอย่าง Compose API ของไลบรารี 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") } } }
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้เพจจิ้งใน Compose ได้ที่เอกสารประกอบเกี่ยวกับรายการและตารางกริด
Maps
คุณสามารถใช้ไลบรารี Maps Compose เพื่อแสดง Google Maps ในแอปได้ ตัวอย่างการใช้งานมีดังนี้
@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" ) } }
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ผลข้างเคียงใน Compose
- สถานะและ Jetpack Compose
- บันทึกสถานะ UI ใน Compose