Vòng đời trong Jetpack Compose Một phần của Android Jetpack.
Các thành phần nhận biết vòng đời thực hiện các hành động để phản hồi một thay đổi trong trạng thái vòng đời của hoạt động lưu trữ. Cấu phần phần mềm androidx.lifecycle.compose cung cấp các API chuyên dụng tự động dọn dẹp tài nguyên khi chúng rời khỏi màn hình hoặc khi ứng dụng chuyển sang chế độ nền.
Các API chính bao gồm:
- Luồng cho
Lifecycle.Statehiện tại. LifecycleEffectscho phép bạn chạy một khối dựa trên mộtLifecycle.Eventcụ thể.
Những công cụ tích hợp này cung cấp các hook thuận tiện để quản lý vòng đời trong hệ phân cấp Compose. Tài liệu này trình bày cách bạn có thể sử dụng những công cụ đó trong ứng dụng của mình.
Thu thập trạng thái vòng đời bằng luồng
Lifecycle hiển thị một thuộc tính currentStateFlow cung cấp Lifecycle.State hiện tại dưới dạng StateFlow Kotlin. Bạn có thể thu thập Flow này dưới dạng State. Việc này cho phép ứng dụng của bạn đọc các thay đổi của Lifecycle trong quá trình kết hợp.
val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow
…
val currentLifecycleState by stateFlow.collectAsState()
Bạn có thể xem ví dụ trước bằng mô-đun lifecycle-common. Phương thức currentStateAsState() có trong mô-đun lifecycle-runtime-compose, cho phép bạn dễ dàng đọc trạng thái của Vòng đời hiện tại chỉ bằng một dòng. Ví dụ sau minh hoạ việc này:
val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()
Chạy mã trên các sự kiện trong vòng đời
Thay vì tạo một lớp riêng biệt triển khai DefaultLifecycleObserver và thêm lớp đó vào vòng đời theo cách thủ công, bạn có thể khai báo logic vòng đời nội tuyến bằng các hiệu ứng cụ thể. LifecycleEffects cho phép bạn chạy một khối khi một Lifecycle.Event cụ thể xảy ra ngay trong thành phần.
LifecycleEventEffect
Sử dụng LifecycleEventEffect để chạy một khối mã khi một sự kiện cụ thể xảy ra. Điều này phù hợp nhất với các sự kiện diễn ra một lần như ghi nhật ký hoặc phân tích, trong đó không cần có kết quả thành công hay kết quả tức thì.
@Composable
fun AnalyticsTracker(screenName: String) {
// Log an event when the app receives ON_RESUME (e.g. comes to foreground)
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
Analytics.logView(screenName)
}
}
LifecycleStartEffect
Đối với các thao tác bắt đầu/dừng theo cặp cần chạy trong khi ứng dụng đang chạy (hiển thị) và dọn dẹp khi ứng dụng dừng (trong nền), hãy sử dụng LifecycleStartEffect.
Tương tự như các hiệu ứng Compose khác (chẳng hạn như LaunchedEffect), LifecycleStartEffect chấp nhận các khoá. Khi thay đổi, khoá sẽ kích hoạt khối để chạy lại.
Khi một sự kiện Lifecycle.Event.ON_STOP xảy ra hoặc hiệu ứng thoát khỏi thành phần, hệ thống sẽ thực thi khối onStopOrDispose để dọn dẹp mọi công việc thuộc khối khởi động.
@Composable
fun LocationMonitor(locationManager: LocationManager) {
// Starts monitoring when ON_START is dispatched
// Stops monitoring when ON_STOP is dispatched
// (or the composable leaves the screen)
LifecycleStartEffect(locationManager) {
val listener = LocationListener { location ->
/* update UI */
}
locationManager.requestLocationUpdates(listener)
// The cleanup block automatically runs on ON_STOP or on disposal
onStopOrDispose {
locationManager.removeUpdates(listener)
}
}
}
Để biết thông tin về các loại hiệu ứng phụ khác, hãy xem bài viết Hiệu ứng phụ trong Compose.
LifecycleResumeEffect
LifecycleResumeEffect hoạt động giống như LifecycleStartEffect, nhưng được liên kết với sự kiện Lifecycle.Event.ON_RESUME. Phương thức này cũng cung cấp một khối onPauseOrDispose để dọn dẹp khi ON_PAUSE được gửi đi hoặc thành phần kết hợp rời khỏi màn hình.
API này hữu ích cho những tài nguyên chỉ cần hoạt động khi người dùng đang tương tác với ứng dụng, chẳng hạn như máy ảnh hoặc ảnh động.
@Composable
fun CameraPreview(cameraController: CameraController) {
LifecycleResumeEffect(cameraController) {
cameraController.startPreview()
onPauseOrDispose {
cameraController.stopPreview()
}
}
}
Truy cập vào LifecycleOwner
Trong Compose, LifecycleOwner có sẵn một cách ngầm định thông qua CompositionLocal có tên là LocalLifecycleOwner. Theo mặc định, máy chủ lưu trữ gốc của hệ phân cấp thành phần sẽ cung cấp chủ sở hữu này.
val lifecycleOwner = LocalLifecycleOwner.current
Đối với nhiều ứng dụng, việc kiểm tra chủ sở hữu mặc định này hoặc truyền chủ sở hữu đó đến các hiệu ứng nhận biết vòng đời là đủ. Tuy nhiên, đối với chế độ điều hướng tuỳ chỉnh hoặc bố cục phức tạp, bạn có thể muốn tạo LifecycleOwner của riêng mình để đặt phạm vi trạng thái vòng đời cho các phần cụ thể của giao diện người dùng. Ví dụ: các thư viện điều hướng (chẳng hạn như Navigation 3) sẽ tự động thực hiện việc này để mỗi màn hình riêng lẻ có vòng đời riêng.
Tạo một LifecycleOwner tuỳ chỉnh
API rememberLifecycleOwner() cho phép bạn tạo và ghi nhớ một LifecycleOwner tuỳ chỉnh. Điều này đặc biệt hữu ích đối với các thành phần như HorizontalPager, trong đó bạn chỉ muốn trang đã hiển thị và ổn định là RESUMED, trong khi đặt maxState là STARTED cho các trang liền kề, ngoài màn hình.
val pagerState = rememberPagerState(pageCount = { 10 })
HorizontalPager(state = pagerState) { pageNum ->
val pageLifecycleOwner = rememberLifecycleOwner(
maxState = if (pagerState.settledPage == pageNum) {
Lifecycle.State.RESUMED
} else {
Lifecycle.State.STARTED
}
)
CompositionLocalProvider(LocalLifecycleOwner provides pageLifecycleOwner) {
// Your pages here. Their lifecycle-aware components respect the
// custom maxState defined above.
}
}
Để biết thêm thông tin về CompositionLocal, hãy xem bài viết Dữ liệu trong phạm vi cục bộ với CompositionLocal.
Phương pháp tốt nhất cho thành phần nhận biết vòng đời
- Hãy giữ cho bộ điều khiển giao diện người dùng tinh gọn nhất có thể. Các lớp này không được thu thập dữ liệu của chính mình; thay vào đó, hãy sử dụng
ViewModelđể làm việc đó và quan sát một đối tượngStateFlowđể phản ánh các thay đổi trở lại giao diện người dùng. - Hãy viết giao diện người dùng theo hướng dữ liệu, trong đó trách nhiệm của bộ điều khiển giao diện người dùng là cập nhật giao diện người dùng dưới dạng các thay đổi về dữ liệu, hoặc thông báo cho người dùng về
ViewModel. - Đưa logic dữ liệu vào lớp
ViewModel.ViewModelsẽ đóng vai trò là trình kết nối giữa bộ điều khiển giao diện người dùng và phần còn lại của ứng dụng. Tuy nhiên, hãy thận trọng vìViewModelkhông có trách nhiệm tìm nạp dữ liệu (ví dụ như từ mạng). Thay vào đó,ViewModelphải gọi thành phần thích hợp để tìm nạp dữ liệu, sau đó cung cấp lại kết quả cho bộ điều khiển giao diện người dùng. - Sử dụng các coroutine Kotlin để quản lý các tác vụ chạy trong thời gian dài và các thao tác khác có thể chạy không đồng bộ.
- Giữ logic bắt đầu/dừng bên trong thành phần kết hợp thực sự cần đến logic đó. Bằng cách này, logic sẽ tự động bị xoá nếu phần tử trên giao diện người dùng cụ thể đó bị xoá khỏi màn hình (ví dụ: bên trong biểu đồ điều hướng hoặc khi khả năng hiển thị có điều kiện).
- Sử dụng
collectAsStateWithLifecyclecho dữ liệu. Không bắt đầu hoặc dừng thu thậpFlowtheo cách thủ công dựa trên các sự kiện trong vòng đời. Thay vào đó, hãy dùngcollectAsStateWithLifecycleđể chuyển đổi các luồng thành trạng thái giao diện người dùng một cách hiệu quả. Điều này giúp tiết kiệm pin và tài nguyên vì cácFlowsẽ tạm dừng khi ứng dụng ở chế độ nền.
Để biết thêm thông tin về Flow, hãy xem phần Các loại trạng thái được hỗ trợ khác.
Trường hợp sử dụng thành phần nhận biết vòng đời
Các thành phần biết vòng đời có thể giúp bạn quản lý vòng đời dễ dàng hơn trong nhiều trường hợp. Một số ví dụ như:
- Chuyển đổi giữa cập nhật vị trí tương đối và chi tiết. Sử dụng
LifecycleStartEffectđể cho phép cập nhật vị trí chi tiết trong khi ứng dụng của bạn hiển thị (ON_START) và tự động dọn dẹp trình nghe hoặc chuyển sang cập nhật tương đối khi ứng dụng chạy dưới nền (ON_STOP). - Dừng và bắt đầu lưu video vào bộ đệm. Sử dụng
LifecycleResumeEffectđể hoãn quá trình phát video thực tế cho đến khi ứng dụng hoàn toàn ở nền trước và có thể tương tác (ON_RESUME), đồng thời đảm bảo rằng quá trình phát sẽ tạm dừng và giải phóng tài nguyên khi ứng dụng chuyển sang nền (ON_PAUSE). - Bắt đầu và dừng truyền phát trực tuyến qua mạng. Sử dụng
collectAsStateWithLifecycleđể theo dõi các luồng dữ liệu liên tục (chẳng hạn như Luồng Kotlin từ một ổ cắm mạng). Điều này giúp bạn cập nhật trực tiếp khi ứng dụng đang chạy ở nền trước và tự động huỷ quá trình thu thập khi ứng dụng chuyển sang chế độ nền. - Tạm dừng và tiếp tục các tác vụ nặng. Sử dụng
LifecycleResumeEffectđể xử lý việc tạm dừng các bản cập nhật hình ảnh có dung lượng lớn khi ứng dụng ở chế độ nền và tiếp tục các bản cập nhật đó sau khi ứng dụng chuyển sang chạy trên nền trước.
Xử lý các sự kiện ON_STOP một cách an toàn
Compose được thiết kế để xử lý các sự kiện ON_STOP một cách an toàn.
- Trạng thái an toàn: Bạn có thể cập nhật
MutableState(ví dụ: bằnguiState.value = ...) bất cứ lúc nào, ngay cả khi ứng dụng ở chế độ nền. Compose sẽ đợi cho đến khi ứng dụng hiển thị để kết xuất các thay đổi. - Dọn dẹp tự động: Với các hiệu ứng như
LifecycleStartEffect, khối dọn dẹp (onStopOrDispose) của bạn sẽ chạy chính xác khi vòng đời chuyển sangSTOPPED. Điều này giúp bạn không phải giữ các tài nguyên nặng (như máy ảnh hoặc vị trí) trong khi ứng dụng ở chế độ nền.
Để biết thêm thông tin về MutableState, hãy xem bài viết Trạng thái và Jetpack Compose.
Tài nguyên khác
Để tìm hiểu thêm về cách xử lý vòng đời của các thành phần nhận biết được vòng đời, hãy tham khảo các tài nguyên bổ sung sau.
Xem nội dung
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Tổng quan về LiveData
- Sử dụng coroutine của Kotlin với các thành phần nhận biết vòng đời
- Mô-đun trạng thái đã lưu cho ViewModel