¿Qué es un Fragment?
Un Fragment es una porción reutilizable de UI con su propio ciclo de vida, que siempre vive dentro de una Activity. Podés pensar en él como una "sub-pantalla" o un módulo visual independiente.
¿Cuándo usar Fragments en lugar de múltiples Activities?
- Navegación moderna: Navigation Component trabaja casi exclusivamente con Fragments.
- Layouts adaptativos: en tablets podés mostrar dos Fragments lado a lado (lista + detalle); en teléfonos, uno a la vez.
- Reutilización: un mismo Fragment puede aparecer en múltiples pantallas.
- Bottom Navigation: cada tab suele ser un Fragment.
La tendencia actualEn apps modernas, la recomendación de Google es tener una sola Activity que actúa como contenedor, y navegar entre Fragments. Eventualmente Jetpack Compose reemplaza todo esto, pero los Fragments siguen siendo fundamentales en apps con View System.
Ciclo de vida de un Fragment
El Fragment tiene su propio ciclo de vida, que está ligado al de su Activity pero agrega pasos propios:
onAttach() // El Fragment se asocia a su Activity
onCreate() // Inicialización sin UI (argumentos, datos)
onCreateView() // Inflá el layout del Fragment — retornás la View
onViewCreated() // La View ya existe — configurá listeners, observadores
onStart() // El Fragment es visible
onResume() // El Fragment está en primer plano
onPause() // Pierde el foco
onStop() // Ya no es visible
onDestroyView() // La View se destruye — liberá referencias a Views
onDestroy() // El Fragment se destruye
onDetach() // Se desasocia de la Activity
onDestroyView vs onDestroyUn Fragment puede tener su View destruida sin que el Fragment en sí se destruya (ej: al navegar con el back stack). Por eso siempre liberá referencias a Views en onDestroyView, no en onDestroy. Si no lo hacés, vas a tener memory leaks.
Crear un Fragment
Creá una clase que extienda Fragment y sobreescribí onCreateView para inflar el layout:
class HomeFragment : Fragment(R.layout.fragment_home) {
// Pasando el layout al constructor — la forma más limpia
// Android se encarga de inflar y destruir la View automáticamente
}
O de forma más explícita si necesitás personalizar el inflado:
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Acá configurás la UI: listeners, observers, etc.
binding.tvTitulo.text = "Hola desde HomeFragment"
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null // MUY IMPORTANTE: evitar memory leaks
}
}
Y su layout res/layout/fragment_home.xml es un XML normal como cualquier layout de Activity.
Agregar un Fragment a la Activity
Hay dos formas: estática (en XML) o dinámica (desde código).
Forma estática — en el XML de la Activity
<!-- activity_main.xml -->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainer"
android:name="ar.pensa.miapp.HomeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Forma dinámica — desde Kotlin
// En MainActivity
supportFragmentManager.commit {
setReorderingAllowed(true)
replace(R.id.fragmentContainer, HomeFragment())
addToBackStack("home") // permite volver con el botón Back
}
TipEn la práctica, si usás Navigation Component (lección 03), casi nunca vas a manipular el FragmentManager directamente. Navigation lo hace por vos de forma más segura.
View Binding en Fragments — el patrón correcto
El patrón _binding / binding que viste arriba es el estándar recomendado. La variable _binding es nullable para poder anularla en onDestroyView. La propiedad binding con !! es segura porque solo la usás entre onViewCreated y onDestroyView.
// Este es el boilerplate que vas a repetir en cada Fragment con ViewBinding:
private var _binding: FragmentXxxBinding? = null
private val binding get() = _binding!!
// En onCreateView: _binding = FragmentXxxBinding.inflate(...)
// En onDestroyView: _binding = null
Comunicación Fragment ↔ Activity
La forma moderna es compartir un ViewModel entre el Fragment y su Activity (o entre Fragments hermanos). Veremos esto en detalle en la lección 04. Brevemente:
// Ambos, Fragment y Activity, acceden al mismo ViewModel
// usando activityViewModels() en el Fragment:
class HomeFragment : Fragment() {
private val viewModel: MainViewModel by activityViewModels()
// Cualquier cambio en el ViewModel es visible para la Activity y otros Fragments
}
Evitá las interfaces de callback (el patrón viejo) y no accedas directamente a la Activity desde el Fragment con (activity as MainActivity).hacerAlgo(). Eso rompe el encapsulamiento y genera crashes si el Fragment se usa en otro contexto.