Kịch bản là một cái activity chứa 2 Fragment MyFragmentWORD và MyFragmentKanji. Khi onCreate thì sẽ nhúng MyFragmentWORD vào trước và thằng MyFragmentKanji sẽ được nhúng khi click vào 1 button trên Activity chính.
nguồn trên internet
Trường hợp 1: khi chạy app thì lần lượt các hàm sẽ là:
MainActivity: onCreate
MyFragmentWORD: onAttach
MainActivity: onAttachFragment
MyFragmentWORD: onCreate
MyFragmentWORD: onCreateView
MyFragmentWORD: onActivityCreated
MyFragmentWORD: onStart
MainActivity: onStart
MainActivity: onPostCreate
MainActivity: onResume
MyFragmentWORD: onResume
MainActivity: onResumeFragments
MainActivity: onPostResume
Rút ra kết luận: Chạy onCreate sau đó tạo xong fragment MyFragmentWORD thì chạy tiếp Activity. Song song với điều này nếu muốn đếm có bao nhiêu fragment trong stack thì cần phải kiểm tra ở hàm onResume của Activity nếu không sẽ không đếm được vì lúc ấy chưa tạo xong fragment.
Trường hợp 2: Khi click vào nút và thêm MyFragmentKanji vào sẽ là:
MyFragmentKANJI: onAttach
MainActivity: onAttachFragment
MyFragmentKANJI: onCreate
MyFragmentKANJI: onCreateView
MyFragmentKANJI: onActivityCreated
MyFragmentKANJI: onStart
MyFragmentKANJI: onResume
Nhìn vào log rút ra kết luận khi click thì Activity vẫn đang ở trạng thái onResume, nếu click thì chỉ chạy vòng đời của fragment này MyFragmentKANJI thôi. Và một đều đặc biệt ếu có bất kỳ một fragment được thêm hay thay thế thì sự kiện onAttachFragment của Activity luôn chạy.
Trường hợp 3: Ấn back trở lại thì fragment MyFragmentKANJI sẽ bị remove.
I/MyFragmentKANJI: onPause
I/MyFragmentKANJI: onStop
I/MyFragmentKANJI: onDestroyView
I/MyFragmentKANJI: onDestroy
I/MyFragmentKANJI: onDetach
Trường hợp 4: Khi đã remove MyFragmentKANJI bằng nút Back, sau đó ra màn hình Home thì
MyFragmentWORD: onPause
MainActivity: onPause
MainActivity: onSaveInstanceState Bundle[{data của bundle}}]
MyFragmentWORD: onStop
MainActivity: onStop
Trường hợp 5: Trở lại app từ trường hợp 4
MainActivity: onRestart
MyFragmentWORD: onStart
MainActivity: onStart
MainActivity: onResume
MyFragmentWORD: onResume
MainActivity: onResumeFragments
MainActivity: onPostResume
Trường hợp 6: Khi chưa remove MyFragmentKANJI bằng Back và ra màn hình Home thì
MyFragmentWORD: onPause
MyFragmentKANJI: onPause
MainActivity: onPause
MainActivity: onSaveInstanceState Bundle[{[{Bundle có data}]
MyFragmentWORD: onStop
MyFragmentKANJI: onStop
MainActivity: onStop
Kết luận: dừng lần lượt các fragment (tùy vào cái nào được thêm vào trước thì dùng trước). Và stop Activity.
Trường hợp 7: Tiếp trường hợp 6 sau khi ra màn hình Home và mở lại app
MainActivity: onRestart
MyFragmentWORD: onStart
MyFragmentKANJI: onStart
MainActivity: onStart
MainActivity: onResume
MyFragmentWORD: onResume
MyFragmentKANJI: onResume
MainActivity: onResumeFragments
MainActivity: onPostResume
Kết luận: Khởi động sự kện onStart của Activity trước sau đó mới gắn Fragment lên Activity.
Bonus:
Khi Activity được tạo thì gắn ồng thời 2 Fragment vào mà không ần click để MyFragmentKANJI hiện lên nữa. Kết quả như sau:
MainActivity: onCreate
MyFragmentWORD: onAttach
MainActivity: onAttachFragment
MyFragmentWORD: onCreate
MyFragmentWORD: onCreateView
MyFragmentWORD: onActivityCreated
MyFragmentKANJI: onAttach
MainActivity: onAttachFragment
MyFragmentKANJI: onCreate
MyFragmentKANJI: onCreateView
MyFragmentKANJI: onActivityCreated
MyFragmentWORD: onStart
MyFragmentKANJI: onStart
MainActivity: onStart
MainActivity: onPostCreate
MainActivity: onResume:
MyFragmentWORD: onResume
MyFragmentKANJI: onResume
MainActivity: onResumeFragments
MainActivity: onPostResume
NOTE QUAN TRỌNG
- Nếu dùng add() Fragment B và dùng addToBackStack() thì Fragment B hiện đè lên Fragment A, nếu B trong suốt thì có thể thấy A bên dưới và khi ấn nút Back thì B bị destroy và để lộ ra Fragment A (Vì Fragment này còn nguyên trên View và trong BackStack chưa bị hủy).
-
Nếu dùng add() Fragment B mà không dùng addToBackStack() thì Fragment B hiện đè lên Fragment A, nếu B trong suốt thì có thể thấy A bên dưới. Nhưng ấn nút Back thì sẽ destroy luôn cả Activity vì bây giờ BackStack không có fragment nào(Lúc gán A lên Activity ở onCreate() cũng không dùng addToBackStack).
-
Nếu dùng replace() Fragment A bằng Fragment B có dùng addToBackStack() thì View A bị xóa khỏi View, View B hiện lên và thêm A vào BackStack. Do đó khi ấn nút Back thì hủy Fragment B sau đó lấy từ BackStack ra Fragment A và hiện A lên View.
-
Nếu dùng replace() Fragment A mà không addToBackStack() thì Fragment B hiện lên, Fragment A bị xóa khỏi View và bị destroy, ấn nút Back thì sẽ destroy luôn cả Activity vì bây giờ BackStack không có fragment nào (Lúc gán A lên Activity ở onCreate() cũng không dùng addToBackStack).
-
Chú ý 1: addBackToStack để lưu trạng thái trước nó chứ không phải nó. ví dụ code này sẽ lưu trạng thái của cái container chứ không lưu trạng thái của fragment SearchWord. Để lưu trạng thái Fragment SearchWord thì cần addToBackStack ở câu lệnh replace hoặc add tiếp theo.
FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.add(R.id.container, new SearchWord(), "SearchWord").addToBackStack(null); transaction.commit();
-
Có thể dùng popBackStack() để xóa 1 fragment ra khỏi stack một cách không đồng bộ.
-
Khi muốn lưu trạng thái của Fragment thì sẽ tến hành lưu ở onPause và restore lại ở onStart().
– onSaveInstanceState() chỉ dùng để lưu trạng thái khi cấu hình thay đổi như xoay màn hình chẳng hạn.
Bài tập và đáp án:
Mình muốn bạn code và chạy thử rồi sau đó nộp bài tại đây. Các câu hỏi này được trích ra từ training file của công ty NTQ Solution Android Development.
1) Vẽ lại lifecyle của Fragment.
2) Vẽ lại diagram mô tả vòng đời của Activity và Fragment cùng nhau. Diagram thể hiện được mối liên kết giữa lifecyle của Activity và lifecyle của Fragment.
Ví dụ: Khi Activity ở trạng thái Created thì callback nào (trạng thái nào) của Fragment được gọi, tương tự cho: Started, Resumed …
3) Cách giao tiếp của Fragment với Activity? Viết demo. (gợi ý thông qua hàm callback và chúng ta sẽ dùng Interface)
4) Viết demo Fragment A truyền data cho Fragment B, Fragment B xử lý xong truyền ngược lại kết quả cho Fragment A. (Gợi ý: dùng setTargetFragment(…) và check onActivityResult() của Fragment)
5) Sử dụng onSaveInstance() trong Fragment. Khi restore data đã save ở onSaveInstance() thì nên restore data đó ở đâu? (onCreate, onCreateView, onActivityCreated …)
6) Trình bày sự khác nhau giữa: replace(), add() của FragmentTransaction?
7) addToBackStack () method của FragmentTransaction dùng làm gì? Vẽ hình mô tả.
8) popBackStack() method của FragmentManager dùng làm gì?
Các bài viết không xem thì tiếc:
- Vòng đời Acivity trong android cơ bản
- Truyền dữ liệu giữa 2 fragment trong android
- Cách dùng Eventbus để truyền dữ liệu trong Android
- Truyền dữ liệu giữa các Activity trong android
- KHÔNG CÀI ĐƯỢC APP TRONG ANDROID
- Chuyển một đối tượng sang Json trong Android
- Lập trình với Recyclerview trong Android – Bài 2 | dotrinh.com
- Lập trình với Recyclerview trong Android – Bài 1 | dotrinh.com
- Lập trình phóng to thu nhỏ ảnh pinch in – pinch out trong Android
- Tạo shortcut cho ứng dụng khi cài Android app programmatically
- Lập trình với Recyclerview trong Android – Bài 3 | dotrinh.com
- Cách dùng AsyncTask trong Android
- Tạo seekbar và kiến thức hữu ích về seekbar trong Android
- Ý nghĩa của clipToPadding trong Android
- Phóng to thu nhỏ trong Android với ScaleGestureDetector