Vòng đời của mảnh

Mỗi phiên bản Fragment đều có vòng đời riêng. Khi một người dùng điều hướng và tương tác với ứng dụng, các phân mảnh sẽ dịch chuyển qua các trạng thái khác nhau của vòng đời khi chúng được thêm, xoá, xuất hiện hoặc thoát khỏi màn hình.

Để quản lý vòng đời, Fragment thực hiện LifecycleOwner, hiển thị một đối tượng Lifecycle có thể được truy cập bằng phương thức getLifecycle().

Mỗi trạng thái Lifecycle sẽ được biểu thị trong enum Lifecycle.State.

Khi thiết lập Fragment trên Lifecycle, bạn có thể sử dụng các kỹ thuật và lớp có sẵn để Điều khiển vòng đời bằng các thành phần nhận biết vòng đời. Ví dụ: bạn có thể hiển thị vị trí của thiết bị trên màn hình bằng cách sử dụng một thành phần nhận biết vòng đời. Thành phần này có khả năng tự động bắt đầu lắng nghe khi phân mảnh được kích hoạt và dừng lại khi phân mảnh chuyển sang trạng thái không hoạt động.

Thay vì sử dụng LifecycleObserver, lớp Fragment chứa các phương thức gọi lại tương ứng với từng thay đổi trong vòng đời của một phân mảnh. Các phương thức này bao gồm onCreate(), onStart(), onResume(),onPause(), onStop()onDestroy().

Giao diện của phân mảnh có Lifecycle riêng biệt được quản lý độc lập với Lifecycle của phân mảnh. Các phân mảnh duy trì một LifecycleOwner cho giao diện của mình, có thể được truy cập bằng getViewLifecycleOwner() hoặc getViewLifecycleOwnerLiveData() Quyền truy cập vào Lifecycle của giao diện sẽ cần thiết trong trường hợp một thành phần nhận biết vòng đời chỉ hoạt động khi tồn tại một giao diện của phân mảnh, chẳng hạn như quan sát LiveData chỉ nhằm mục đích hiển thị trên màn hình.

Chủ đề này sẽ bàn chi tiết về vòng đời của Fragment, giải thích một số quy tắc xác định trạng thái vòng đời của phân mảnh và chỉ ra mối quan hệ giữa các trạng thái Lifecycle và các lệnh gọi lại trong vòng đời của phân mảnh.

Các phân mảnh và trình quản lý phân mảnh

Khi một phân mảnh được sao chép, nó sẽ bắt đầu ở trạng thái INITIALIZED. Để dịch chuyển trong phần còn lại của vòng đời, phân mảnh phải được đưa vào một FragmentManager. FragmentManager có trách nhiệm xác định trạng thái của phân mảnh và chuyển chúng sang trạng thái đó.

Ngoài vòng đời phân mảnh, FragmentManager còn có trách nhiệm đính kèm các phân mảnh vào hoạt động của máy chủ và tách chúng ra khi phân mảnh không còn được sử dụng. Lớp Fragment có hai phương thức gọi lại là onAttach()onDetach() có thể được ghi đè để sử dụng khi một trong hai hoạt động này diễn ra.

Lệnh gọi lại onAttach() được bật khi phân mảnh đã được thêm vào FragmentManager và được đính kèm vào hoạt động của máy chủ. Tại thời điểm này, phân mảnh đang hoạt động và FragmentManager đang quản lý trạng thái vòng đời của nó. Khi đó, các phương thức FragmentManager như findFragmentById() sẽ trả phân mảnh này về lại.

onAttach() luôn được gọi trước khi diễn ra mọi sự thay đổi trạng thái vòng đời.

Lệnh gọi lại onDetach() được bật khi phân mảnh đã bị xoá khỏi FragmentManager và được tách khỏi hoạt động của máy chủ. Phân mảnh ngừng hoạt động và không thể truy xuất bằng findFragmentById() nữa.

onDetach() luôn được gọi sau khi diễn ra mọi sự thay đổi trạng thái vòng đời.

Lưu ý rằng các lệnh gọi lại này không liên quan đến các phương thức FragmentTransaction attach()detach(). Để biết thêm thông tin về các phương thức này, hãy xem Giao dịch phân mảnh.

Các trạng thái vòng đời của mảnh và lệnh gọi lại

Khi xác định trạng thái vòng đời của phân mảnh, FragmentManager sẽ xem xét các điểm sau:

  • Trạng thái cực đại của phân mảnh được xác định theo FragmentManager của nó. Phân mảnh không thể hoạt động vượt quá trạng thái của FragmentManager của nó.
  • Là một chức năng của FragmentTransaction, bạn có thể thiết lập trạng thái vòng đời cực đại cho phân mảnh bằng cách sử dụng setMaxLifecycle() .
  • Trạng thái vòng đời của phân mảnh không bao giờ được lớn hơn trạng thái gốc. Ví dụ: một phân mảnh gốc hay một hoạt động gốc phải được khởi động trước các phân mảnh con của chúng. Tương tự, các phân mảnh con phải được dừng lại trước phân mảnh gốc hay hoạt động gốc.
Các trạng thái vòng đời của phân mảnh và mối quan hệ của chúng với các lệnh gọi lại trong vòng đời của phân mảnh và vòng đời giao diện của phân mảnh
Hình 1. Trạng thái Lifecycle của mảnh và mối quan hệ giữa chúng với phương thức gọi lại trong vòng đời của mảnh và thành phần hiển thị Lifecycle của mảnh.

Hình 1 cho thấy từng trạng thái Lifecycle của mảnh và mối liên hệ giữa chúng với phương thức gọi lại trong vòng đời của mảnh và thành phần hiển thị Lifecycle của mảnh.

Khi phân mảnh hoạt động trong suốt vòng đời của mình, nó sẽ dịch chuyển lên và xuống qua các trạng thái. Ví dụ: một phân mảnh được xếp vào phần trên cùng của back stack sẽ dịch chuyển theo hướng đi lên từ CREATED đến STARTED đến RESUMED. Ngược lại, khi một phân mảnh bị bật ra khỏi back stack, nó sẽ dịch chuyển theo hướng đi xuống qua các trạng thái đó, từ RESUMED đến STARTED đến CREATED và cuối cùng là DESTROYED.

Dịch chuyển trạng thái đi lên

Khi dịch chuyển đi lên qua các trạng thái vòng đời, trước tiên, phân mảnh sẽ thực hiện lệnh gọi lại vòng đời liên kết với trạng thái mới của mình. Sau khi lệnh gọi lại này hoàn tất, Lifecycle.Event liên quan sẽ được phát cho người quan sát bởi Lifecycle của phân mảnh, tiếp theo là Lifecycle của giao diện nếu đã được sao chép.

Phân mảnh ĐƯỢC TẠO

Khi phân mảnh đạt đến trạng thái CREATED, nó đã được thêm vào FragmentManager và phương thức onAttach() đã được gọi.

Đây là lúc thích hợp để khôi phục mọi trạng thái đã lưu liên kết với chính phân mảnh đó thông qua SavedStateRegistry của phân mảnh. Lưu ý lúc này giao diện của phân mảnh vẫn chưa được tạo và mọi trạng thái liên kết với giao diện của phân mảnh chỉ được khôi phục sau khi giao diện đã được tạo.

Quá trình dịch chuyển này sẽ kích hoạt lệnh onCreate(). Lệnh gọi lại này cũng nhận được một đối số savedInstanceStateBundle chứa mọi trạng thái đã được onSaveInstanceState() lưu trước đó. Lưu ý savedInstanceState có giá trị null vào lần đầu tiên tạo mảnh, nhưng giá trị này luôn khác rỗng trong các lần tái tạo tiếp theo, ngay cả khi không ghi đè onSaveInstanceState(). Hãy xem phần Lưu trạng thái với các phân mảnh để biết thêm chi tiết.

Phân mảnh ĐƯỢC TẠO và Chế độ xem ĐƯỢC KHỞI CHẠY

Lifecycle của giao diện của phân mảnh chỉ được tạo khi Fragment cung cấp một phiên bản View hợp lệ. Trong hầu hết trường hợp, có thể sử dụng Hàm tạo phân mảnh để lấy @LayoutId với chức năng tự động phóng to giao diện tại thời điểm thích hợp. Cũng có thể ghi đè onCreateView() để tự động phóng to hoặc tạo giao diện của phân mảnh.

Chỉ khi giao diện của phân mảnh được sao chép với một View không phải là null (khuyết), View đó sẽ được thiết lập trên phân mảnh và có thể được truy xuất bằng getView(). Sau đó, getViewLifecycleOwnerLiveData() sẽ được cập nhật bằng INITIALIZEDLifecycleOwner mới, tương ứng với giao diện của phân mảnh. Lệnh gọi lại onViewCreated() cũng được gọi tại thời điểm này.

Đây là lúc thích hợp để thiết lập trạng thái ban đầu của giao diện, nhằm bắt đầu quan sát các phiên bản LiveData với lệnh gọi lại có chức năng cập nhật giao diện của phân mảnh và để thiết lập bộ chuyển đổi trên mọi phiên bản RecyclerView hoặc ViewPager2 trong giao diện của phân mảnh.

Phân mảnh và Chế độ xem ĐƯỢC TẠO

Sau khi giao diện của phân mảnh đã được tạo, trạng thái trước đó (nếu có) của giao diện sẽ được khôi phục, và Lifecycle của giao diện sẽ được chuyển sang trạng thái CREATED. Chủ sở hữu vòng đời của giao diện cũng sẽ phát ON_CREATE cho người quan sát. Ở đây, bạn nên khôi phục mọi trạng thái bổ sung liên kết với giao diện của phân mảnh.

Quá trình chuyển đổi này cũng bật lệnh gọi lại onViewStateRestored().

Phân mảnh và Chế độ xem ĐƯỢC BẮT ĐẦU

Cần liên kết các thành phần nhận biết vòng đời với trạng thái STARTED của phân mảnh, vì trạng thái này sẽ đảm bảo giao diện của phân mảnh có sẵn nếu đã được tạo và có thể thực hiện FragmentTransaction an toàn trên phần tử con FragmentManager của phân mảnh. Nếu giao diện của phân mảnh không phải là giá trị null, Lifecycle của giao diện sẽ được chuyển đến STARTED ngay sau Lifecycle của phân mảnh được chuyển đến STARTED.

Khi phân mảnh ở trạng thái STARTED, lệnh gọi lại onStart() sẽ được bật lên.

Phân mảnh và Chế độ xem ĐƯỢC TIẾP TỤC

Khi phân mảnh ở chế độ hiển thị, tất cả các hiệu ứng AnimatorTransition đã hoàn tất và phân mảnh đã sẵn sàng cho tương tác của người dùng. Lifecycle của phân mảnh chuyển sang trạng thái RESUMED và lệnh gọi lại onResume() sẽ được bật lên.

Việc chuyển sang RESUMED là một tín hiệu tin cậy cho thấy người dùng lúc này có thể tương tác với phân mảnh. Những phân mảnh không phải là RESUMED không được thiết lập tiêu điểm trên giao diện theo cách thủ công hoặc thử điều khiển chế độ hiển thị phương thức nhập.

Dịch chuyển trạng thái xuống dưới

Khi một phân mảnh dịch chuyển xuống trạng thái vòng đời thấp hơn, Lifecycle.Event liên quan sẽ được phát cho người quan sát bởi Lifecycle của giao diện nếu được sao chép, tiếp đến là Lifecycle của phân mảnh. Sau khi sự kiện vòng đời của phân mảnh được phát, phân mảnh sẽ gọi lệnh gọi lại vòng đời liên kết.

Phân mảnh và Chế độ xem ĐƯỢC BẮT ĐẦU

Khi người dùng bắt đầu rời khỏi phân mảnh, và trong khi phân mảnh đó vẫn còn hiển thị, Lifecycle của phân mảnh và giao diện của nó được chuyển trở lại trạng thái STARTED và phát ON_PAUSE cho người quan sát. Sau đó, phân mảnh sẽ bật lệnh gọi lại onPause().

Phân mảnh và Chế độ xem ĐƯỢC TẠO

Khi phân mảnh không còn hiển thị, các Lifecycle của phân mảnh và giao diện của phân mảnh sẽ được chuyển sang trạng thái CREATED và phát ON_STOP cho người quan sát. Quá trình chuyển đổi trạng thái này diễn ra không chỉ do hoạt động gốc hay phân mảnh gốc bị ngừng hoạt động mà còn do việc lưu trạng thái của hoạt động gốc hay phân mảnh gốc. Việc này đảm bảo ON_STOP sẽ được bật trước khi lưu trạng thái của phân mảnh. Nhờ đó, ON_STOP trở thành điểm cuối cùng an toàn để thực hiện FragmentTransaction trên phần tử con FragmentManager.

Như minh hoạ trên hình 2, thứ tự của lệnh gọi lại onStop() và quá trình lưu trạng thái với onSaveInstanceState() còn tuỳ theo cấp độ API. Đối với tất cả các cấp độ API trước API 28, onSaveInstanceState() sẽ được gọi trước onStop(). Đối với API cấp 28 trở lên, thứ tự gọi được đảo ngược.

sự khác biệt về thứ tự gọi của onStop() và onSaveInstanceState()
Hình 2. Sự khác biệt về thứ tự gọi của onStop()onSaveInstanceState().

Phân mảnh ĐƯỢC TẠO và Chế độ xem BỊ HUỶ BỎ

Sau khi tất cả ảnh động và quá trình chuyển đổi của giai đoạn kết thúc đã hoàn tất và giao diện của phân mảnh đã được tách khỏi cửa sổ, Lifecycle của giao diện sẽ được chuyển vào trạng thái DESTROYED và phát ON_DESTROY cho người quan sát. Sau đó, phân mảnh sẽ bật lệnh gọi lại onDestroyView(). Lúc này, giao diện của phân mảnh đã kết thúc vòng đời và getViewLifecycleOwnerLiveData() trả về giá trị null.

Khi đó, tất cả các tham chiếu đến giao diện của phân mảnh phải được xoá, cho phép giao diện của phân mảnh được đưa vào thùng rác.

Phân mảnh BỊ HUỶ BỎ

Nếu mảnh bị xoá hoặc nếu FragmentManager bị huỷ bỏ, Lifecycle của mảnh sẽ được chuyển sang trạng thái DESTROYED và gửi sự kiện ON_DESTROY cho trình quan sát. Sau đó, phân mảnh sẽ bật lệnh gọi lại onDestroy(). Tại thời điểm này, phân mảnh này kết thúc vòng đời của mình.

Tài nguyên khác

Để biết thêm thông tin liên quan đến vòng đời của phân mảnh, hãy xem các tài nguyên bổ sung sau.

Hướng dẫn

Blog