Bạn có thể sử dụng các thư viện yêu thích trong Compose. Mục này mô tả cách kết hợp một số thư viện hữu ích nhất.
Hoạt động
Để sử dụng Compose trong một hoạt động, bạn phải sử dụng
ComponentActivity
,
một lớp con của Activity
cung cấp LifecycleOwner
thích hợp và
các thành phần cho Compose. Lớp con này cũng cung cấp các API bổ sung giúp tách mã
khỏi các phương thức ghi đè trong lớp hoạt động của bạn.
Activity Compose hiển thị những API này với các thành phần kết hợp sao cho không cần phải ghi đè những phương thức diễn ra bên ngoài các thành phần kết hợp hoặc truy xuất một thực thể Activity
rõ ràng.
Thêm vào đó, các API này đảm bảo chúng chỉ được khởi chạy một lần, duy trì quá trình tái cấu trúc, đồng thời dọn dẹp đúng cách nếu thành phần kết hợp bị xoá khỏi cấu trúc.
Kết quả hoạt động
API
rememberLauncherForActivityResult()
cho phép bạn
nhận kết quả từ một hoạt động
trong thành phần kết hợp của bạn:
@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" ) } }
Ví dụ này minh hoạ một hợp đồng GetContent()
đơn giản. Nhấn vào nút để khởi chạy yêu cầu. Cú pháp trailing Lambda cho
rememberLauncherForActivityResult()
được dẫn ra khi người dùng chọn một hình ảnh và quay lại hoạt động khởi chạy.
Thao tác này tải hình ảnh đã chọn bằng hàm rememberImagePainter()
của Coil.
Bạn có thể sử dụng bất kỳ
lớp con nào củaActivityResultContract
làm đối số đầu tiên cho
rememberLauncherForActivityResult()
.
Tức là bạn có thể sử dụng kỹ thuật này để yêu cầu nội dung từ khung và các mẫu phổ biến khác. Bạn cũng có thể tạo các hợp đồng tuỳ chỉnh của riêng mình và sử dụng chúng bằng kỹ thuật này.
Yêu cầu quyền khi bắt đầu chạy
Bạn có thể dùng cùng một Activity Result API (API Kết quả hoạt động) và rememberLauncherForActivityResult()
đã trình bày ở trên để yêu cầu cấp quyền khi bắt đầu chạy bằng cách sử dụng hợp đồng RequestPermission
để được cấp một quyền hoặc sử dụng hợp đồng RequestMultiplePermissions
để được cấp nhiều quyền.
Thư viện Quyền truy cập nhóm thư viện cũng có thể được sử dụng một lớp phía trên các API đó để liên kết trạng thái hiện tại đã cấp cho các quyền truy cập vào Trạng thái mà công cụ Compose có thể sử dụng.
Xử lý nút quay lại hệ thống
Để cung cấp hoạt động điều hướng quay lại tuỳ chỉnh và ghi đè chế độ mặc định của nút quay lại hệ thống từ bên trong thành phần kết hợp của bạn, thành phần kết hợp này có thể sử dụng hàm BackHandler
để can thiệp vào sự kiện đó:
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
Đối số đầu tiên kiểm soát mã BackHandler
có đang được bật hay không; bạn có thể sử dụng đối số này để tạm thời tắt trình xử lý dựa trên trạng thái của thành phần. Biểu thức lambda tạo vệt sẽ được gọi nếu
người dùng kích hoạt sự kiện quay lại hệ thống và
BackHandler
hiện đang bật.
ViewModel
Nếu sử dụng thư viện Thành phần cấu trúc ViewModel, bạn có thể truy cập vào ViewModel
từ bất kỳ thành phần kết hợp nào bằng cách gọi hàm viewModel()
. Thêm phần phụ thuộc sau vào tệp Gradle:
Groovy
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") }
Sau đó, bạn có thể sử dụng hàm viewModel()
trong mã của mình.
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
trả về một chế độ ViewModel
hiện có hoặc tạo một chế độ mới. Theo mặc định, ViewModel
được trả về nằm trong phạm vi của hoạt động bao quanh, mảnh hoặc đích điều hướng, đồng thời được giữ lại chừng nào phạm vi còn hoạt động.
Ví dụ: nếu sử dụng thành phần kết hợp trong một hoạt động, viewModel()
sẽ trả về cùng một phiên bản cho đến khi hoạt động đó kết thúc hoặc quá trình kết thúc.
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 ) { /* ... */ }
Nguyên tắc sử dụng
Bạn thường truy cập vào các thực thể ViewModel
ở thành phần kết hợp cấp màn hình, tức là gần với một thành phần kết hợp gốc được gọi từ một hoạt động, mảnh hoặc đích đến của biểu đồ Điều hướng. Điều này là do theo mặc định, ViewModel
được đưa vào phạm vi của các đối tượng cấp màn hình đó. Đọc thêm về vòng đời và phạm vi của ViewModel
tại đây.
Cố gắng tránh truyền các thực thể ViewModel
xuống các thành phần kết hợp khác vì điều này có thể khiến các thành phần kết hợp đó khó kiểm thử hơn và có thể làm hỏng bản xem trước. Thay vào đó, hãy chỉ truyền dữ liệu và các hàm cần thiết dưới dạng tham số.
Bạn có thể sử dụng các thực thể ViewModel
để quản lý trạng thái cho các thành phần kết hợp cấp màn hình phụ, tuy nhiên, hãy lưu ý đến vòng đời và phạm vi của ViewModel
. Nếu thành phần kết hợp là độc lập, bạn nên cân nhắc sử dụng Hilt để chèn ViewModel
nhằm tránh phải truyền các phần phụ thuộc từ thành phần kết hợp mẹ.
Nếu ViewModel
có các phần phụ thuộc, viewModel()
sẽ lấy ViewModelProvider.Factory
tuỳ ý làm tham số.
Để biết thêm thông tin về ViewModel
trong Compose và cách sử dụng các phiên bản với thư viện Compose Navigation, hoặc các hoạt động và mảnh, vui lòng xem tài liệu về Khả năng tương tác.
Trình phát dữ liệu trực tuyến
Compose đi kèm với phần mở rộng cho các giải pháp dựa trên chế độ phát trực tuyến phổ biến nhất của Android. Mỗi phần mở rộng trong số này được một cấu phần phần mềm khác nhau cung cấp:
LiveData.observeAsState()
có trong cấu phần phần mềmandroidx.compose.runtime:runtime-livedata:$composeVersion
.Flow.collectAsState()
không yêu cầu thêm phần phụ thuộc.Observable.subscribeAsState()
có trong cấu phần phần mềmandroidx.compose.runtime:runtime-rxjava2:$composeVersion
hoặcandroidx.compose.runtime:runtime-rxjava3:$composeVersion
.
Các cấu phần phần mềm này đăng ký dưới dạng trình nghe và thể hiện các giá trị dưới dạng một State
. Bất cứ khi nào có giá trị mới
được đưa ra, công cụ Compose sẽ kết hợp lại các phần đó của giao diện người dùng nơi
sử dụng state.value
. Ví dụ: trong mã này, ShowData
sẽ kết hợp lại mỗi khi
exampleLiveData
đưa ra một giá trị mới.
// 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) } }
Thao tác không đồng bộ trong công cụ Compose
Jetpack Compose cho phép bạn thực thi các thao tác không đồng bộ bằng cách sử dụng coroutine từ trong những thành phần kết hợp của bạn.
Hãy xem các API LaunchedEffect
, produceState
và rememberCoroutineScope
trong
tài liệu về hiệu ứng lề để biết thêm
thông tin.
Di chuyển
Thành phần điều hướng hỗ trợ các ứng dụng sử dụng công cụ Jetpack Compose. Hãy xem phần Điều hướng bằng Compose và Di chuyển điều hướng Jetpack sang Navigation Compose để biết thêm thông tin.
Hilt
Hilt là giải pháp được đề xuất để chèn phần phụ thuộc vào các ứng dụng Android, giải pháp này hoạt động liền mạch với Compose.
Hàm viewModel()
được đề cập trong Mục ViewModel sẽ tự động sử dụng ViewModel mà Hilt tạo ra với chú thích @HiltViewModel
. Chúng tôi đã cung cấp cho bạn tài liệu với thông tin về Tích hợp ViewModel của 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 và điều hướng
Hilt cũng tích hợp với thư viện Navigation Compose. Thêm các phần phụ thuộc bổ sung sau đây vào tệp Gradle của bạn:
Groovy
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.2.0") }
Khi sử dụng tính năng Navigation Compose, hãy luôn sử dụng hàm kết hợp hiltViewModel
để có được bản sao của @HiltViewModel
có chú thích ViewModel
.
Tính năng này hoạt động với các mảnh hoặc hoạt động được chú giải bằng @AndroidEntryPoint
.
Ví dụ: nếu ExampleScreen
là một đích đến trong một biểu đồ điều hướng, hãy gọi hiltViewModel()
để lấy thực thể của ExampleViewModel
trong phạm vi đích đến được hiển thị trong đoạn mã dưới đây:
// 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) } /* ... */ } }
Nếu bạn cần truy xuất bản sao của ViewModel
nằm trong phạm vi tuyến đường điều hướng hoặc sơ đồ điều hướng thay thế, sử dụng hàm có khả năng kết hợp hiltViewModel
và truyền tham số backStackEntry
tương ứng:
// 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
Thư viện
Paging
giúp bạn tải dữ liệu dễ dàng hơn và tính năng này được hỗ trợ trong công cụ Compose.
Trang phát hành
Paging có chứa
thông tin về phần phụ thuộc paging-compose
bổ sung cần được thêm vào
dự án và phiên bản của dự án đó.
Dưới đây là một ví dụ về các API Compose của thư viện 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") } } }
Hãy xem Tài liệu về Danh sách và lưới để biết thêm thông tin về cách sử dụng tính năng Phân trang trong Compose.
Maps
Bạn có thể sử dụng thư viện Maps Compose để tích hợp Google Maps vào ứng dụng của mình. Sau đây là ví dụ về cách sử dụng:
@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" ) } }
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Những hiệu ứng phụ trong ứng dụng Compose
- Trạng thái và Jetpack Compose
- Lưu trạng thái giao diện người dùng trong Compose