Skip to Content

Fragments trong Android

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?

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:

  • Ư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

class HomeFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { setContent { HomeScreen() } } } }

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

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

// Trong Activity supportFragmentManager.commit { replace(R.id.fragment_container, HomeFragment()) addToBackStack(null) } // Trong Fragment parentFragmentManager.commit { replace(R.id.fragment_container, DetailFragment.newInstance(123)) addToBackStack(null) }

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

// SharedViewModel class SharedViewModel : ViewModel() { private val _selectedItem = MutableLiveData<Item>() val selectedItem: LiveData<Item> = _selectedItem fun selectItem(item: Item) { _selectedItem.value = item } } // Fragment A sharedViewModel.selectItem(item) // Fragment B sharedViewModel.selectedItem.observe(viewLifecycleOwner) { item -> // Handle selected item }

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

<!-- activity_main.xml --> <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

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

AspectFragmentCompose
UIXML ViewsComposables
LifecycleComplexSimplified
NavigationFragmentManagerNavController
StateViewModel + LiveDataState + ViewModel
ReusabilityFragment.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.

Last updated on