Fragments
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Fragment là một phần UI có thể tái sử dụng, có lifecycle riêng, nằm trong Activity.
Lưu ý: Với Jetpack Compose, việc sử dụng Fragment giảm đáng kể. Tuy nhiên, hiểu Fragment vẫn quan trọng cho legacy projects và một số use cases.
2. Khi nào dùng Fragment?
Phần tiêu đề “2. Khi nào dùng Fragment?”Nên dùng Fragment khi:
Phần tiêu đề “Nên dùng Fragment khi:”- Làm việc với XML Views (legacy)
- Multi-pane layouts (tablet)
- Bottom Navigation với Fragment
- Integration với third-party libraries yêu cầu Fragment
Với Compose:
Phần tiêu đề “Với Compose:”- Ưu tiên Navigation Compose
- Không cần Fragment cho hầu hết use cases
- Có thể dùng Fragment để host Compose UI nếu cần
3. Tạo Fragment cơ bản
Phần tiêu đề “3. Tạo Fragment cơ bản”class HomeFragment : Fragment() {
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { setContent { HomeScreen() } } }}4. Fragment Lifecycle
Phần tiêu đề “4. Fragment Lifecycle”Fragment Added │ ▼onAttach() → onCreate() → onCreateView() → onViewCreated() │ ▼onStart() → onResume() │ ▼ (User interacts) │onPause() → onStop() │ ▼onDestroyView() → onDestroy() → onDetach()class MyFragment : Fragment() {
override fun onAttach(context: Context) { super.onAttach(context) Log.d(TAG, "onAttach") }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.d(TAG, "onCreate") }
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { Log.d(TAG, "onCreateView") return inflater.inflate(R.layout.fragment_my, container, false) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Log.d(TAG, "onViewCreated") }
override fun onDestroyView() { super.onDestroyView() Log.d(TAG, "onDestroyView") }
override fun onDestroy() { super.onDestroy() Log.d(TAG, "onDestroy") }}5. Fragment với Arguments
Phần tiêu đề “5. Fragment với Arguments”class DetailFragment : Fragment() {
companion object { private const val ARG_ID = "id"
fun newInstance(id: Int): DetailFragment { return DetailFragment().apply { arguments = Bundle().apply { putInt(ARG_ID, id) } } } }
private val itemId: Int by lazy { arguments?.getInt(ARG_ID) ?: 0 }
override fun onCreateView(...): View { return ComposeView(requireContext()).apply { setContent { DetailScreen(itemId) } } }}6. FragmentManager
Phần tiêu đề “6. FragmentManager”// Trong ActivitysupportFragmentManager.commit { replace(R.id.fragment_container, HomeFragment()) addToBackStack(null)}
// Trong FragmentparentFragmentManager.commit { replace(R.id.fragment_container, DetailFragment.newInstance(123)) addToBackStack(null)}7. Fragment với ViewModel
Phần tiêu đề “7. Fragment với ViewModel”class HomeFragment : Fragment() {
// Scoped to Fragment private val viewModel: HomeViewModel by viewModels()
// Shared with Activity private val sharedViewModel: SharedViewModel by activityViewModels()
override fun onCreateView(...): View { return ComposeView(requireContext()).apply { setContent { val state by viewModel.uiState.collectAsState() HomeScreen(state) } } }}8. Fragment Communication
Phần tiêu đề “8. Fragment Communication”Shared ViewModel (Recommended)
Phần tiêu đề “Shared ViewModel (Recommended)”// SharedViewModelclass SharedViewModel : ViewModel() { private val _selectedItem = MutableLiveData<Item>() val selectedItem: LiveData<Item> = _selectedItem
fun selectItem(item: Item) { _selectedItem.value = item }}
// Fragment AsharedViewModel.selectItem(item)
// Fragment BsharedViewModel.selectedItem.observe(viewLifecycleOwner) { item -> // Handle selected item}Fragment Result API
Phần tiêu đề “Fragment Result API”// Fragment A (listener)setFragmentResultListener("requestKey") { key, bundle -> val result = bundle.getString("resultKey")}
// Fragment B (sender)setFragmentResult("requestKey", bundleOf("resultKey" to "Result"))9. Bottom Navigation với Fragments
Phần tiêu đề “9. Bottom Navigation với Fragments”<androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" app:navGraph="@navigation/nav_graph" app:defaultNavHost="true" />
<com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" app:menu="@menu/bottom_nav_menu" />class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager .findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController
findViewById<BottomNavigationView>(R.id.bottom_nav) .setupWithNavController(navController) }}10. Compose trong Fragment
Phần tiêu đề “10. Compose trong Fragment”class ComposeFragment : Fragment() {
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed ) setContent { MaterialTheme { MyComposeScreen() } } } }}📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Aspect | Fragment | Compose |
|---|---|---|
| UI | XML Views | Composables |
| Lifecycle | Complex | Simplified |
| Navigation | FragmentManager | NavController |
| State | ViewModel + LiveData | State + ViewModel |
| Reusability | Fragment.newInstance() | @Composable functions |
Khuyến nghị: Với dự án mới, ưu tiên Jetpack Compose và Navigation Compose. Chỉ dùng Fragment khi thực sự cần thiết.