Bỏ qua để đến nội dung

Fragments

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.

  • 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
  • Ư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
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
HomeScreen()
}
}
}
}
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")
}
}
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)
}
}
}
}
// 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)
}
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)
}
}
}
}
// 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 A (listener)
setFragmentResultListener("requestKey") { key, bundle ->
val result = bundle.getString("resultKey")
}
// Fragment B (sender)
setFragmentResult("requestKey", bundleOf("resultKey" to "Result"))
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)
}
}
class ComposeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
)
setContent {
MaterialTheme {
MyComposeScreen()
}
}
}
}
}

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.