Khi người dùng di chuyển qua, ra khỏi và quay lại ứng dụng của bạn, các thực thể Activity trong ứng dụng sẽ chuyển đổi qua nhiều trạng thái trong vòng đời của chúng.
Lớp Activity cung cấp một số lệnh gọi lại cho phép hoạt động biết khi nào trạng thái thay đổi hoặc khi hệ thống đang tạo, dừng hoặc tiếp tục một hoạt động hoặc huỷ bỏ quy trình chứa hoạt động đó.
Trong các phương thức gọi lại trong vòng đời, bạn có thể khai báo cách hoạt động của mình hoạt động khi người dùng rời khỏi và vào lại hoạt động. Ví dụ: nếu đang xây dựng một trình phát video trực tuyến, bạn có thể tạm dừng video và chấm dứt kết nối mạng khi người dùng chuyển sang một ứng dụng khác. Khi người dùng quay lại, bạn có thể kết nối lại với mạng và cho phép người dùng tiếp tục xem video từ cùng một vị trí.
Mỗi lệnh gọi lại cho phép bạn thực hiện công việc cụ thể phù hợp với một thay đổi trạng thái nhất định. Việc thực hiện đúng công việc vào đúng thời điểm và xử lý các chuyển đổi đúng cách sẽ giúp ứng dụng của bạn hoạt động mạnh mẽ và hiệu quả hơn. Ví dụ: việc triển khai tốt các phương thức gọi lại trong vòng đời có thể giúp ứng dụng của bạn tránh được những vấn đề sau:
- Ứng dụng gặp sự cố nếu người dùng nhận được cuộc gọi điện thoại hoặc chuyển sang một ứng dụng khác trong khi đang dùng ứng dụng của bạn.
- Tiêu tốn tài nguyên hệ thống có giá trị khi người dùng không chủ động sử dụng.
- Mất tiến trình của người dùng nếu họ rời khỏi ứng dụng của bạn và quay lại sau đó.
- Gặp sự cố hoặc mất tiến trình của người dùng khi màn hình xoay giữa hướng ngang và hướng dọc.
Tài liệu này giải thích chi tiết về vòng đời của activity. Tài liệu này bắt đầu bằng cách mô tả mô hình vòng đời. Tiếp theo, tài liệu này giải thích từng lệnh gọi lại: điều gì xảy ra trong nội bộ khi các lệnh gọi lại thực thi và những gì bạn cần triển khai trong các lệnh gọi lại đó.
Sau đó, tài liệu này sẽ giới thiệu ngắn gọn về mối quan hệ giữa trạng thái hoạt động và lỗ hổng bảo mật của một quy trình khiến hệ thống buộc phải tắt quy trình đó. Cuối cùng, tài liệu này thảo luận về một số chủ đề liên quan đến việc chuyển đổi giữa các trạng thái hoạt động.
Để biết thông tin về cách xử lý vòng đời, bao gồm cả hướng dẫn về các phương pháp hay nhất, hãy xem phần Vòng đời trong Jetpack Compose và Lưu trạng thái giao diện người dùng. Để tìm hiểu cách xây dựng một ứng dụng mạnh mẽ, đủ tiêu chuẩn phát hành công khai bằng cách sử dụng các hoạt động kết hợp với thành phần cấu trúc, hãy xem Hướng dẫn về cấu trúc ứng dụng.
Các khái niệm về vòng đời hoạt động
Để điều hướng quá trình chuyển đổi giữa các giai đoạn trong vòng đời của activity, lớp Activity cung cấp một tập hợp cốt lõi gồm 6 lệnh gọi lại: onCreate, onStart, onResume, onPause, onStop và onDestroy. Hệ thống sẽ gọi từng lệnh gọi lại này khi hoạt động chuyển sang một trạng thái mới.
Hình 1 trình bày hình ảnh minh hoạ cho mô hình này.
Khi người dùng bắt đầu rời khỏi hoạt động, hệ thống sẽ gọi các phương thức để huỷ bỏ hoạt động. Trong một số trường hợp, hoạt động chỉ bị huỷ một phần và vẫn nằm trong bộ nhớ, chẳng hạn như khi người dùng chuyển sang một ứng dụng khác. Trong những trường hợp này, hoạt động vẫn có thể quay lại nền trước.
Nếu người dùng quay lại hoạt động, thì hoạt động đó sẽ tiếp tục từ nơi người dùng rời đi. Ngoại trừ một số trường hợp, ứng dụng bị hạn chế bắt đầu hoạt động khi chạy ở chế độ nền.
Khả năng hệ thống tắt một quy trình nhất định, cùng với các hoạt động trong quy trình đó, phụ thuộc vào trạng thái của hoạt động tại thời điểm đó. Để biết thêm thông tin về mối quan hệ giữa trạng thái và khả năng bị loại bỏ, hãy xem phần trạng thái hoạt động và loại bỏ khỏi bộ nhớ.
Tuỳ thuộc vào độ phức tạp của hoạt động, có thể bạn không cần triển khai tất cả các phương thức trong vòng đời. Tuy nhiên, bạn cần hiểu rõ từng loại và triển khai những loại giúp ứng dụng của bạn hoạt động theo cách người dùng mong đợi.
Compose và vòng đời
Trong Compose, hãy tránh đặt logic nghiệp vụ hoặc chế độ thiết lập trình quan sát thủ công ngay trong các lệnh gọi lại hoạt động như onStart hoặc onResume. Thay vào đó, hãy sử dụng các hiệu ứng nhận biết Vòng đời và trình quan sát nhận biết trạng thái tự động điều chỉnh theo sự hiện diện của giao diện người dùng trên màn hình.
- Thu thập nhận biết vòng đời: Sử dụng
collectAsStateWithLifecycleđể sử dụng các luồng từViewModel. API này tự động bắt đầu thu thập khi giao diện người dùng chuyển sang trạng thái Đã bắt đầu và dừng khi giao diện người dùng chuyển sang nền, giúp ngăn chặn việc tiêu thụ tài nguyên không cần thiết. Sau khi thu thập luồng dưới dạng trạng thái, bạn có thể sử dụngLifecycleEffectsđể chạy mã khi một sự kiện trong vòng đời xảy ra. - Luồng logic: Bằng cách sử dụng các API này, giao diện người dùng sẽ phản ứng với trạng thái vòng đời một cách tự nhiên thông qua cây thành phần, đảm bảo rằng logic nghiệp vụ chỉ thực thi khi người dùng đang tương tác tích cực với thành phần.
Để biết thêm về Compose và vòng đời, hãy xem bài viết Vòng đời trong Jetpack Compose.
Phương thức gọi lại trong vòng đời
Phần này cung cấp thông tin về khái niệm và cách triển khai các phương thức gọi lại được dùng trong vòng đời của activity.
Một số hành động thuộc về các phương thức vòng đời của activity. Tuy nhiên, hãy đặt mã triển khai các hành động của một thành phần phụ thuộc vào thành phần đó, thay vì phương thức vòng đời của activity. Để làm được việc này, bạn cần làm cho thành phần phụ thuộc nhận biết được vòng đời. Để tìm hiểu cách làm cho các thành phần phụ thuộc nhận biết được vòng đời, hãy xem bài viết Vòng đời trong Jetpack Compose.
onCreate
Bạn phải triển khai lệnh gọi lại này. Lệnh này sẽ kích hoạt khi hệ thống tạo hoạt động lần đầu tiên. Khi được tạo, hoạt động sẽ chuyển sang trạng thái Đã tạo. Trong phương thức onCreate, hãy thực hiện logic khởi động ứng dụng cơ bản chỉ xảy ra một lần trong toàn bộ vòng đời của hoạt động.
Ví dụ: việc triển khai onCreate có thể liên kết dữ liệu với danh sách, liên kết hoạt động với ViewModel và tạo thực thể cho một số biến phạm vi lớp. Phương thức này nhận tham số savedInstanceState, là một đối tượng Bundle chứa trạng thái đã lưu trước đó của hoạt động. Nếu hoạt động chưa từng tồn tại trước đây, thì giá trị của đối tượng Bundle sẽ rỗng.
Nếu bạn có một thành phần nhận biết được vòng đời được kết nối với vòng đời của hoạt động, thì thành phần đó sẽ nhận được sự kiện ON_CREATE. Phương thức được chú thích bằng @OnLifecycleEvent được gọi để thành phần nhận biết vòng đời có thể thực hiện bất kỳ mã thiết lập nào cần thiết cho trạng thái đã tạo.
Ví dụ sau đây cho thấy cách tích hợp một composable Text trong một Hoạt động tối thiểu:
class ExampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // In here, we can call composables! MaterialTheme { Greeting(name = "compose") } } } } @Composable fun Greeting(name: String) { Text(text = "Hello $name!") }
Hoạt động của bạn không duy trì ở trạng thái Created (Đã tạo). Sau khi phương thức onCreate thực thi xong, hoạt động sẽ chuyển sang trạng thái Đã bắt đầu và hệ thống sẽ gọi các phương thức onStart và onResume liên tiếp nhau.
onStart
Khi hoạt động chuyển sang trạng thái Đã bắt đầu, hệ thống sẽ gọi onStart.
Lệnh gọi này giúp người dùng nhìn thấy hoạt động khi ứng dụng chuẩn bị cho hoạt động chuyển sang nền trước và có thể tương tác. Ví dụ: phương thức này là nơi khởi chạy mã duy trì giao diện người dùng.
Khi hoạt động chuyển sang trạng thái Đã bắt đầu, mọi thành phần nhận biết vòng đời được liên kết với vòng đời của hoạt động sẽ nhận được sự kiện ON_START.
Phương thức onStart hoàn tất nhanh chóng và giống như trạng thái Created (Đã tạo), hoạt động không duy trì ở trạng thái Started (Đã bắt đầu). Sau khi lệnh gọi lại này kết thúc, hoạt động sẽ chuyển sang trạng thái Đã tiếp tục và hệ thống sẽ gọi phương thức onResume.
onResume
Khi hoạt động chuyển sang trạng thái Đã tiếp tục, hoạt động đó sẽ xuất hiện trên nền trước và hệ thống sẽ gọi lệnh gọi lại onResume. Đây là trạng thái mà ứng dụng
tương tác với người dùng. Ứng dụng sẽ duy trì trạng thái này cho đến khi có sự kiện nào đó khiến ứng dụng mất tiêu điểm, chẳng hạn như thiết bị nhận được cuộc gọi điện thoại, người dùng chuyển đến một hoạt động khác hoặc màn hình thiết bị tắt.
Khi hoạt động chuyển sang trạng thái Đã tiếp tục, mọi thành phần nhận biết vòng đời được liên kết với vòng đời của hoạt động sẽ nhận được sự kiện ON_RESUME. Đây là nơi các thành phần vòng đời có thể bật mọi chức năng cần chạy trong khi thành phần hiển thị và ở nền trước, chẳng hạn như bắt đầu xem trước camera.
Khi một sự kiện gián đoạn xảy ra, hoạt động sẽ chuyển sang trạng thái Tạm dừng và hệ thống sẽ gọi lệnh gọi lại onPause.
Nếu hoạt động quay lại trạng thái Đã tiếp tục từ trạng thái Đã tạm dừng, thì hệ thống sẽ gọi lại phương thức onResume. Vì lý do này, hãy triển khai onResume để khởi động các thành phần mà bạn phát hành trong onPause và thực hiện mọi hoạt động khởi động khác phải diễn ra mỗi khi hoạt động chuyển sang trạng thái Đã tiếp tục.
Dưới đây là ví dụ về một thành phần nhận biết vòng đời truy cập vào máy ảnh khi thành phần đó nhận được sự kiện ON_RESUME:
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun initializeCamera() {
if (camera == null) {
getCamera()
}
}
...
}
Đoạn mã trước đó sẽ khởi chạy máy ảnh sau khi LifecycleObserver nhận được sự kiện ON_RESUME. Tuy nhiên, ở chế độ nhiều cửa sổ, hoạt động của bạn có thể hiển thị đầy đủ ngay cả khi ở trạng thái Tạm dừng. Ví dụ: khi ứng dụng ở chế độ nhiều cửa sổ và người dùng nhấn vào cửa sổ không chứa hoạt động của bạn, hoạt động của bạn sẽ chuyển sang trạng thái Tạm dừng.
Nếu bạn chỉ muốn máy ảnh hoạt động khi ứng dụng được Tiếp tục (hiển thị và hoạt động ở nền trước), hãy khởi chạy máy ảnh sau sự kiện ON_RESUME được minh hoạ trước đó. Nếu bạn muốn duy trì hoạt động của camera trong khi hoạt động bị tạm dừng nhưng vẫn hiển thị, chẳng hạn như ở chế độ nhiều cửa sổ, hãy khởi chạy camera sau sự kiện ON_START.
Tuy nhiên, việc để máy ảnh hoạt động trong khi hoạt động của bạn ở trạng thái Tạm dừng có thể khiến một ứng dụng khác ở trạng thái Đã tiếp tục trong chế độ nhiều cửa sổ không truy cập được vào máy ảnh. Đôi khi, bạn cần phải duy trì hoạt động của máy ảnh trong khi hoạt động của bạn bị Tạm dừng, nhưng việc này có thể làm giảm trải nghiệm tổng thể của người dùng.
Vì lý do này, hãy suy nghĩ kỹ về thời điểm thích hợp nhất trong vòng đời để kiểm soát tài nguyên hệ thống dùng chung trong bối cảnh chế độ nhiều cửa sổ. Để tìm hiểu thêm về cách hỗ trợ chế độ nhiều cửa sổ, hãy xem bài viết Hỗ trợ chế độ nhiều cửa sổ.
Bất kể bạn chọn sự kiện tích luỹ nào để thực hiện thao tác khởi chạy, hãy nhớ sử dụng sự kiện trong vòng đời tương ứng để giải phóng tài nguyên. Nếu bạn khởi chạy một thành phần sau sự kiện ON_START, hãy giải phóng hoặc chấm dứt thành phần đó sau sự kiện ON_STOP. Nếu bạn khởi chạy sau sự kiện ON_RESUME, hãy phát hành sau sự kiện ON_PAUSE.
Đoạn mã trước đó đặt mã khởi chạy camera trong một thành phần nhận biết vòng đời. Thay vào đó, bạn có thể đưa mã này trực tiếp vào các phương thức gọi lại trong vòng đời của activity, chẳng hạn như onStart và onStop, nhưng bạn không nên làm như vậy. Việc thêm logic này vào một thành phần độc lập, nhận biết vòng đời cho phép bạn sử dụng lại thành phần đó trên nhiều hoạt động mà không cần sao chép mã. Để tìm hiểu cách tạo thành phần nhận biết vòng đời, hãy xem bài viết Vòng đời trong Jetpack Compose.
onPause
Hệ thống gọi phương thức này như dấu hiệu đầu tiên cho thấy người dùng đang rời khỏi hoạt động của bạn, mặc dù điều này không phải lúc nào cũng có nghĩa là hoạt động đang bị huỷ. Trạng thái này cho biết hoạt động không còn ở nền trước nhưng vẫn hiển thị nếu người dùng đang ở chế độ nhiều cửa sổ. Có một số lý do khiến một hoạt động có thể chuyển sang trạng thái này:
- Một sự kiện làm gián đoạn quá trình thực thi ứng dụng, như mô tả trong phần về lệnh gọi lại
onResume, sẽ tạm dừng hoạt động hiện tại. Đây là trường hợp phổ biến nhất. - Ở chế độ nhiều cửa sổ, chỉ có một ứng dụng được lấy tiêu điểm tại bất kỳ thời điểm nào và hệ thống sẽ tạm dừng tất cả các ứng dụng khác.
- Việc mở một hoạt động mới, bán trong suốt (chẳng hạn như hộp thoại) sẽ tạm dừng hoạt động mà nó che phủ. Miễn là hoạt động hiển thị một phần nhưng không được chú ý, hoạt động đó vẫn bị tạm dừng.
Khi một hoạt động chuyển sang trạng thái Tạm dừng, mọi thành phần nhận biết vòng đời được liên kết với vòng đời của hoạt động đó sẽ nhận được sự kiện ON_PAUSE. Đây là nơi các thành phần vòng đời có thể dừng mọi chức năng không cần chạy trong khi thành phần không ở nền trước, chẳng hạn như dừng xem trước camera.
Sử dụng phương thức onPause để tạm dừng hoặc điều chỉnh các thao tác không thể tiếp tục hoặc có thể tiếp tục ở mức vừa phải, trong khi Activity ở trạng thái Tạm dừng và bạn dự kiến sẽ sớm tiếp tục.
Bạn cũng có thể sử dụng phương thức onPause để giải phóng tài nguyên hệ thống, xử lý các cảm biến (như GPS) hoặc bất kỳ tài nguyên nào ảnh hưởng đến thời lượng pin trong khi hoạt động của bạn bị tạm dừng và người dùng không cần đến các tài nguyên đó.
Tuy nhiên, như đã đề cập trong phần về onResume, một hoạt động bị tạm dừng vẫn có thể hiển thị đầy đủ nếu ứng dụng đang ở chế độ nhiều cửa sổ. Hãy cân nhắc sử dụng onStop thay vì onPause để giải phóng hoặc điều chỉnh hoàn toàn các tài nguyên có liên quan và thao tác liên quan đến giao diện người dùng nhằm hỗ trợ chế độ nhiều cửa sổ tốt hơn.
Ví dụ sau đây về LifecycleObserver phản ứng với sự kiện ON_PAUSE là đối tác của ví dụ về sự kiện ON_RESUME trước đó, giải phóng máy ảnh khởi chạy sau khi nhận được sự kiện ON_RESUME:
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun releaseCamera() {
camera?.release()
camera = null
}
...
}
Ví dụ này đặt mã giải phóng camera sau khi LifecycleObserver nhận được sự kiện ON_PAUSE.
Quá trình thực thi onPause diễn ra rất nhanh và không nhất thiết phải cung cấp đủ thời gian để thực hiện các thao tác lưu. Vì lý do này, đừng sử dụng onPause để lưu dữ liệu người dùng hoặc ứng dụng, thực hiện lệnh gọi mạng hoặc thực thi giao dịch cơ sở dữ liệu.
Công việc đó có thể không hoàn tất trước khi phương thức hoàn tất.
Thay vào đó, hãy thực hiện các thao tác tắt máy có tải nặng trong onStop. Để biết thêm thông tin về các thao tác phù hợp cần thực hiện trong onStop, hãy xem phần tiếp theo. Để biết thêm thông tin về cách lưu dữ liệu, hãy xem phần lưu và khôi phục trạng thái.
Việc hoàn tất phương thức onPause không có nghĩa là hoạt động sẽ rời khỏi trạng thái Tạm dừng. Thay vào đó, hoạt động vẫn ở trạng thái này cho đến khi hoạt động tiếp tục hoặc hoàn toàn không hiển thị với người dùng. Nếu hoạt động tiếp tục, hệ thống sẽ gọi lại lệnh gọi lại onResume một lần nữa.
Nếu hoạt động quay lại trạng thái Đã tiếp tục từ trạng thái Đã tạm dừng, thì hệ thống sẽ giữ bản sao Activity trong bộ nhớ, gọi lại bản sao đó khi hệ thống gọi onResume. Trong trường hợp này, bạn không cần khởi chạy lại các thành phần được tạo trong bất kỳ phương thức gọi lại nào dẫn đến trạng thái Đã tiếp tục. Nếu hoạt động hoàn toàn không hiển thị, hệ thống sẽ gọi onStop.
onStop
Khi người dùng không còn nhìn thấy hoạt động của bạn, hoạt động đó sẽ chuyển sang trạng thái Đã dừng và hệ thống sẽ gọi lệnh gọi lại onStop. Điều này có thể xảy ra khi một hoạt động mới ra mắt chiếm toàn bộ màn hình. Hệ thống cũng gọi onStop khi hoạt động chạy xong và sắp kết thúc.
Khi hoạt động chuyển sang trạng thái Đã dừng, mọi thành phần nhận biết vòng đời được liên kết với vòng đời của hoạt động sẽ nhận được sự kiện ON_STOP. Đây là nơi các thành phần vòng đời có thể dừng mọi chức năng không cần chạy trong khi thành phần không xuất hiện trên màn hình.
Trong phương thức onStop, hãy giải phóng hoặc điều chỉnh các tài nguyên không cần thiết khi người dùng không nhìn thấy ứng dụng. Ví dụ: ứng dụng của bạn có thể tạm dừng ảnh động hoặc chuyển từ cập nhật vị trí chi tiết sang cập nhật vị trí tương đối. Việc sử dụng onStop thay vì onPause có nghĩa là công việc liên quan đến giao diện người dùng vẫn tiếp tục, ngay cả khi người dùng đang xem hoạt động của bạn ở chế độ nhiều cửa sổ.
Ngoài ra, hãy sử dụng onStop để thực hiện các thao tác tắt tương đối tốn CPU. Ví dụ: nếu không tìm được thời điểm thích hợp hơn để lưu thông tin vào cơ sở dữ liệu, bạn có thể thực hiện việc này trong onStop. Ví dụ sau đây cho thấy cách triển khai onStop để lưu nội dung của ghi chú nháp vào bộ nhớ ổn định:
override fun onStop() {
super.onStop()
// Delegate the save operation to the ViewModel, which handles the
// background thread operations (e.g., using Kotlin Coroutines and Room).
noteViewModel.saveDraft()
}
Khi hoạt động của bạn chuyển sang trạng thái Đã dừng, đối tượng Activity sẽ được lưu giữ trong bộ nhớ: đối tượng này duy trì tất cả thông tin về trạng thái và thành viên, nhưng không được đính kèm vào trình quản lý cửa sổ. Khi hoạt động tiếp tục, hoạt động sẽ gọi lại thông tin này.
Từ trạng thái Đã dừng, hoạt động sẽ quay lại để tương tác với người dùng hoặc hoạt động sẽ kết thúc và biến mất. Nếu hoạt động quay lại, hệ thống sẽ gọi onRestart. Nếu Activity chạy xong, hệ thống sẽ gọi onDestroy.
onDestroy
onDestroy được gọi trước khi hoạt động bị huỷ. Hệ thống gọi lệnh gọi lại này vì một trong hai lý do:
- Hoạt động đang kết thúc do người dùng đóng hoàn toàn hoạt động hoặc do
finishđược gọi trong hoạt động. - Hệ thống đang tạm thời huỷ hoạt động do thay đổi cấu hình, chẳng hạn như xoay thiết bị hoặc chuyển sang chế độ nhiều cửa sổ.
Khi hoạt động chuyển sang trạng thái bị huỷ, mọi thành phần nhận biết vòng đời được liên kết với vòng đời của hoạt động đều nhận được sự kiện ON_DESTROY. Đây là nơi các thành phần vòng đời có thể dọn dẹp mọi thứ cần thiết trước khi Activity bị huỷ.
Thay vì đưa logic vào Activity để xác định lý do bị huỷ, hãy sử dụng đối tượng ViewModel để chứa dữ liệu khung hiển thị có liên quan cho Activity. Nếu Activity được tạo lại do thay đổi cấu hình, thì ViewModel không cần làm gì cả vì nó được giữ nguyên và được cung cấp cho thực thể Activity tiếp theo.
Nếu Activity không được tạo lại, thì ViewModel sẽ có lệnh gọi phương thức onCleared, trong đó phương thức này có thể dọn dẹp mọi dữ liệu cần thiết trước khi bị huỷ. Bạn có thể phân biệt hai trường hợp này bằng phương thức isFinishing.
Nếu hoạt động đang kết thúc, onDestroy là phương thức gọi lại trong vòng đời cuối cùng mà hoạt động nhận được. Nếu onDestroy được gọi do thay đổi cấu hình, thì hệ thống sẽ ngay lập tức tạo một thực thể hoạt động mới, sau đó gọi onCreate trên thực thể mới đó trong cấu hình mới.
Lệnh gọi lại onDestroy giải phóng tất cả tài nguyên chưa được giải phóng bằng các lệnh gọi lại trước đó, chẳng hạn như onStop.
Trạng thái hoạt động và việc loại bỏ khỏi bộ nhớ
Hệ thống sẽ loại bỏ các quy trình khi cần giải phóng RAM. Khả năng hệ thống buộc tắt một quy trình nhất định phụ thuộc vào trạng thái của quy trình đó tại thời điểm đó. Đến lượt mình, trạng thái quy trình phụ thuộc vào trạng thái của hoạt động đang chạy trong quy trình. Bảng 1 cho thấy mối tương quan giữa trạng thái quy trình, trạng thái hoạt động và khả năng hệ thống tắt quy trình. Bảng này chỉ áp dụng nếu một quy trình không chạy các loại thành phần của ứng dụng khác.
Khả năng bị giết |
Trạng thái quy trình |
Trạng thái hoạt động cuối cùng |
Thấp nhất |
Nền trước (đang hoặc sắp được lấy tiêu điểm) |
Đã tiếp tục |
Thấp |
Hiển thị (không có tiêu điểm) |
Đã bắt đầu/Đã tạm dừng |
Cao hơn |
Nền (không hiển thị) |
Stopped (Đã dừng) |
Cao nhất |
Trống |
Đã huỷ bỏ |
Bảng 1. Mối quan hệ giữa vòng đời của quy trình và trạng thái hoạt động.
Hệ thống không bao giờ trực tiếp tắt một hoạt động để giải phóng bộ nhớ. Thay vào đó, hệ thống sẽ buộc tắt quy trình mà hoạt động chạy trong đó, không chỉ huỷ hoạt động mà còn huỷ mọi thứ khác đang chạy trong quy trình. Để tìm hiểu cách duy trì và khôi phục trạng thái giao diện người dùng của hoạt động khi xảy ra sự kiện bị buộc tắt do hệ thống gây ra, hãy xem phần lưu và khôi phục trạng thái.
Người dùng cũng có thể loại bỏ một quy trình bằng cách sử dụng Trình quản lý ứng dụng trong phần Cài đặt để loại bỏ ứng dụng tương ứng.
Để biết thêm thông tin về quy trình, hãy xem bài viết Tổng quan về quy trình và luồng.
Lưu và khôi phục trạng thái giao diện người dùng tạm thời
Người dùng muốn trạng thái giao diện người dùng của một hoạt động vẫn giữ nguyên trong suốt quá trình thay đổi cấu hình, chẳng hạn như khi thực hiện thao tác xoay hoặc khi chuyển sang chế độ nhiều cửa sổ. Tuy nhiên, theo mặc định, hệ thống sẽ huỷ hoạt động khi xảy ra thay đổi về cấu hình như vậy, xoá sạch mọi trạng thái giao diện người dùng đã lưu trong thực thể của hoạt động đó.
Tương tự, người dùng muốn trạng thái giao diện người dùng vẫn giữ nguyên nếu họ tạm thời chuyển từ ứng dụng của bạn sang một ứng dụng khác rồi quay lại ứng dụng của bạn sau đó. Tuy nhiên, hệ thống có thể huỷ bỏ quy trình của ứng dụng trong khi người dùng thoát ra ngoài và hoạt động của bạn bị dừng.
Khi các quy tắc ràng buộc của hệ thống huỷ bỏ hoạt động, hãy duy trì trạng thái giao diện người dùng tạm thời của người dùng bằng cách kết hợp ViewModel (cho logic nghiệp vụ phức tạp và trạng thái màn hình), API rememberSaveable của Jetpack Compose (cho trạng thái giao diện người dùng gọn nhẹ) và/hoặc bộ nhớ cục bộ. Để tìm hiểu thêm về kỳ vọng của người dùng so với hành vi của hệ thống và cách tốt nhất để duy trì dữ liệu trạng thái giao diện người dùng phức tạp trong hoạt động do hệ thống khởi tạo và quá trình bị buộc tắt, hãy xem bài viết Lưu trạng thái giao diện người dùng.
rememberSaveable tự động duy trì cả các thay đổi về cấu hình và
sự kiện bị buộc tắt do hệ thống gây ra bằng cách gói trạng thái trong hệ thống, mang lại
trải nghiệm liền mạch mà không cần mã nguyên mẫu ở cấp hoạt động.
Trạng thái thực thể
Có một vài trường hợp hoạt động của bạn bị huỷ do hành vi bình thường của ứng dụng, chẳng hạn như khi người dùng nhấn nút Quay lại hoặc hoạt động của bạn báo hiệu việc tự huỷ bằng cách gọi phương thức finish.
Khi hoạt động của bạn bị huỷ do người dùng nhấn nút Quay lại hoặc hoạt động tự kết thúc, thì cả hệ thống và người dùng đều không còn khái niệm về thực thể Activity đó nữa. Trong những trường hợp này, kỳ vọng của người dùng khớp với hành vi của hệ thống và bạn không cần làm gì thêm.
Tuy nhiên, nếu hệ thống huỷ hoạt động do các quy tắc ràng buộc của hệ thống (chẳng hạn như thay đổi cấu hình hoặc áp lực bộ nhớ), thì mặc dù thực thể Activity thực tế đã biến mất, hệ thống vẫn nhớ rằng thực thể đó đã tồn tại. Nếu người dùng cố gắng quay lại hoạt động, hệ thống sẽ tạo một thực thể mới của hoạt động đó bằng cách sử dụng một tập hợp dữ liệu đã lưu mô tả trạng thái của hoạt động khi hoạt động đó bị huỷ.
Dữ liệu đã lưu mà hệ thống sử dụng để khôi phục trạng thái trước đó được gọi là trạng thái thực thể. Về cơ bản, đây là một tập hợp các cặp khoá-giá trị. Theo mặc định, hệ thống sẽ sử dụng trạng thái thực thể để lưu thông tin cơ bản về bố cục của giao diện người dùng, chẳng hạn như văn bản do người dùng nhập hoặc vị trí cuộn.
Bạn có thể kết nối với hành vi này của hệ thống bằng cách sử dụng rememberSaveable. Nếu thực thể hoạt động của bạn bị huỷ và được tạo lại, thì mọi trạng thái giao diện người dùng được gói trong rememberSaveable sẽ tự động được khôi phục mà bạn không cần thêm mã cấp hoạt động.
Tuy nhiên, hoạt động của bạn có thể sẽ có thông tin trạng thái phức tạp hơn mà bạn muốn khôi phục, chẳng hạn như dữ liệu người dùng, phản hồi mạng hoặc biến thành viên theo dõi tiến trình của người dùng. Cơ chế trạng thái thực thể (và theo đó là rememberSaveable) không phù hợp để lưu giữ lượng dữ liệu lớn hơn mức thông thường, vì cơ chế này yêu cầu chuyển đổi tuần tự trên luồng chính và tiêu thụ bộ nhớ của quy trình hệ thống.
Để lưu trữ nhiều hơn một lượng dữ liệu rất nhỏ, hãy áp dụng phương pháp kết hợp sử dụng bộ nhớ cục bộ liên tục, lớp ViewModel và tính năng nâng trạng thái của Compose, như được nêu trong phần Lưu trạng thái giao diện người dùng.
Lưu trạng thái giao diện người dùng đơn giản, gọn nhẹ bằng rememberSaveable
Khi hoạt động của bạn bắt đầu dừng, hệ thống sẽ chuẩn bị lưu thông tin trạng thái vào một gói trạng thái thực thể. Để kết nối với hành vi này của hệ thống, bạn sử dụng rememberSaveable ngay trong các hàm composable.
rememberSaveable tự động lưu và khôi phục trạng thái tạm thời của giao diện người dùng, chẳng hạn như
văn bản do người dùng nhập hoặc vị trí cuộn, trong quá trình tạo lại hoạt động.
Để lưu thông tin trạng thái tuỳ chỉnh, gọn nhẹ (chẳng hạn như tiến trình của người dùng trong một trò chơi), hãy khai báo trạng thái của bạn bằng rememberSaveable. Khung Compose xử lý việc chuyển đổi tuần tự sang gói trạng thái thực thể:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Để lưu dữ liệu cố định, chẳng hạn như lựa chọn ưu tiên của người dùng hoặc dữ liệu cho cơ sở dữ liệu, hãy tận dụng các cơ hội thích hợp khi hoạt động của bạn đang ở nền trước. Nếu không có cơ hội như vậy, hãy lưu dữ liệu cố định trong phương thức onStop.
Khôi phục trạng thái giao diện người dùng của hoạt động bằng trạng thái thực thể đã lưu
Khi hoạt động của bạn được tạo lại sau khi bị huỷ trước đó, quá trình khôi phục trạng thái sẽ tự động diễn ra. Khi sử dụng rememberSaveable, bạn không cần phải viết bất kỳ logic khôi phục rõ ràng nào, kiểm tra các gói rỗng hoặc ghi đè lệnh gọi lại hoạt động. Mã khởi chạy và lưu trạng thái cũng khôi phục trạng thái một cách liền mạch khi hoạt động quay trở lại:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Hoạt động và điều hướng
Một ứng dụng có thể chuyển đổi giữa các màn hình nhiều lần trong suốt thời gian hoạt động, chẳng hạn như khi người dùng nhấn vào nút Quay lại của thiết bị hoặc chọn một đích đến mới. Các ứng dụng Android hiện đại thường sử dụng cấu trúc hoạt động đơn.
Thay vì bắt đầu một Activity mới cho mỗi màn hình, ứng dụng của bạn sẽ lưu trữ một Activity duy nhất và sử dụng thành phần Navigation để hoán đổi các màn hình có khả năng kết hợp trong hoạt động đó.
Để tìm hiểu cách triển khai tính năng điều hướng hiện đại, ưu tiên Compose, hãy xem hướng dẫn về thư viện Navigation 3 của Jetpack Compose.
Bắt đầu một hoạt động từ một hoạt động khác
Một hoạt động có thể cần bắt đầu một hoạt động khác tại một thời điểm nào đó. Ví dụ: nhu cầu này phát sinh khi một ứng dụng cần chuyển từ màn hình hiện tại sang màn hình mới.
Tuỳ thuộc vào việc hoạt động của bạn có muốn nhận kết quả từ hoạt động mới mà nó sắp bắt đầu hay không, bạn có thể bắt đầu hoạt động mới bằng phương thức startActivity hoặc phương thức startActivityForResult. Trong cả hai trường hợp, bạn đều truyền vào một đối tượng Intent.
Đối tượng Intent chỉ định hoạt động chính xác mà bạn muốn bắt đầu hoặc mô tả loại hành động bạn muốn thực hiện. Hệ thống sẽ chọn hoạt động phù hợp cho bạn, thậm chí có thể là từ một ứng dụng khác. Đối tượng Intent cũng có thể mang một lượng nhỏ dữ liệu để hoạt động được bắt đầu sử dụng. Để biết thêm thông tin về lớp Intent, hãy xem bài viết Ý định và bộ lọc ý định.
startActivity
Nếu hoạt động mới bắt đầu không cần trả về kết quả, thì hoạt động hiện tại có thể bắt đầu hoạt động đó bằng cách gọi phương thức startActivity.
Khi làm việc trong ứng dụng của riêng mình, bạn thường chỉ cần chạy một hoạt động đã biết. Ví dụ: đoạn mã sau đây cho thấy cách chạy một hoạt động có tên là SignInActivity.
val context = LocalContext.current
Button(onClick = {
val intent = Intent(context, SignInActivity::class.java)
context.startActivity(intent)
}) {
Text("Sign In")
}
Bắt đầu hoạt động bên ngoài
Mặc dù hoạt động điều hướng nội bộ trong ứng dụng do Navigation xử lý, nhưng đôi khi Activity của bạn sẽ cần bắt đầu các hoạt động khác. Điều này thường xảy ra khi bạn muốn tận dụng một ứng dụng bên ngoài để thực hiện một hành động cụ thể, chẳng hạn như mở trình duyệt web, gửi email hoặc chụp ảnh.
Để đạt được điều này, bạn sử dụng đối tượng Intent để mô tả loại hành động bạn muốn thực hiện và hệ thống sẽ khởi chạy hoạt động thích hợp từ một ứng dụng khác.
Ví dụ: nếu muốn cho phép người dùng gửi nội dung email, bạn có thể tạo ý định sau:
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)
Nếu bạn cần chạy một hoạt động bên ngoài và nhận lại kết quả (chẳng hạn như yêu cầu ứng dụng máy ảnh chụp ảnh và trả về hình ảnh), hãy sử dụng API kết quả Activity hiện đại thay vì lệnh gọi lại startActivityForResult không dùng nữa.
Hoạt động điều phối
Khi một hoạt động bắt đầu một hoạt động khác, cả hai hoạt động đều trải qua quá trình chuyển đổi vòng đời. Hoạt động đầu tiên sẽ ngừng hoạt động và chuyển sang trạng thái Tạm dừng hoặc Đã dừng, trong khi hoạt động kia được tạo. Trong trường hợp các hoạt động này chia sẻ dữ liệu được lưu vào đĩa hoặc nơi khác, bạn cần hiểu rằng hoạt động đầu tiên không hoàn toàn dừng lại trước khi hoạt động thứ hai được tạo. Thay vào đó, quá trình bắt đầu hoạt động thứ hai sẽ trùng lặp với quá trình dừng hoạt động thứ nhất.
Thứ tự của các phương thức gọi lại trong vòng đời được xác định rõ ràng, đặc biệt là khi hai Hoạt động nằm trong cùng một quy trình (nói cách khác là cùng một ứng dụng) và một Hoạt động đang bắt đầu Hoạt động còn lại. Dưới đây là thứ tự các thao tác xảy ra khi Hoạt động A bắt đầu Hoạt động B:
- Phương thức
onPausecủa Hoạt động A thực thi. - Các phương thức
onCreate,onStartvàonResumecủa Hoạt động B thực thi theo trình tự. Hoạt động B hiện được người dùng chú ý. - Nếu Hoạt động A không còn hiển thị trên màn hình, thì phương thức
onStopcủa hoạt động này sẽ thực thi.
Trình tự các phương thức gọi lại trong vòng đời này cho phép bạn quản lý quá trình chuyển đổi thông tin từ hoạt động này sang hoạt động khác.
Tài nguyên khác
Để tìm hiểu thêm về vòng đời của activity, hãy xem các tài nguyên bổ sung sau: