Fragment Lifecycle es una secuencia estrictamente definida de métodos callback que Android invoca durante la vida de un Fragment: desde la creación (onAttach) hasta la eliminación completa (onDetach). Fragment tiene un ciclo de vida más complejo que Activity — incluye 11 estados y 7 callbacks principales. Fragment Lifecycle se gestiona a través de FragmentManager y está estrechamente vinculado al ciclo de vida de la Activity que lo contiene. Según Google, Fragment se utiliza en el 74% de las aplicaciones Android que funcionan en API Level 21+, lo que hace que comprender Fragment Lifecycle sea obligatorio para el desarrollo profesional de Android. La documentación de Android sobre Fragment Lifecycle describe todos los estados y garantías de llamada.
Aspectos clave
Fragment Lifecycle es un conjunto de estados y métodos interconectados por los que pasa cada instancia de Fragment desde su creación hasta su destrucción. A diferencia de Activity, el ciclo de vida de Fragment está vinculado a dos contextos: el propio Fragment (vive de onAttach a onDetach) y su View (vive de onCreateView a onDestroyView). Esta separación es una característica clave de Fragment, que permite sobrevivir a la destrucción de la View al rotar la pantalla sin destruir el propio Fragment.
Secuencia completa de callbacks de Fragment:
Según Google, el fragmento promedio en una aplicación moderna pasa por el ciclo completo de 3 a 5 veces por sesión de usuario (debido a rotaciones de pantalla y navegación). El manejo correcto de todas las fases es la base de la estabilidad de la UI.
FragmentManager gestiona Fragment a través de cinco estados principales, definidos en la clase Fragment.State. Cada estado corresponde a un conjunto específico de callbacks que se han ejecutado.
| Estado | Significado | Callbacks ejecutados |
|---|---|---|
| INITIALIZED | Fragment está creado, pero la View aún no está disponible | onAttach, onCreate |
| CREATED | La View está creada, pero Fragment no es visible | + onCreateView, onViewCreated |
| STARTED | Fragment es visible, pero no activo | + onStart |
| RESUMED | Fragment está activo, interactúa con el usuario | + onResume |
| DESTROYED | Fragment está destruido | + onDestroyView, onDestroy, onDetach |
FragmentManager mueve Fragment entre estados según las acciones del usuario y los eventos del sistema. Al agregar Fragment a un contenedor, pasa secuencialmente por INITIALIZED → CREATED → STARTED → RESUMED. Al eliminarlo — RESUMED → STARTED → CREATED → DESTROYED.
El estado CREATED es especial: la View puede destruirse (después de onDestroyView), pero el propio Fragment permanece en el estado CREATED (después de onDestroyView, antes de onDestroy). Esto permite que FragmentManager mantenga el Fragment en memoria sin View, lo que es necesario para sobrevivir a las rotaciones de pantalla.
Fragment Lifecycle y Activity Lifecycle están estrechamente relacionados pero tienen diferencias fundamentales. Fragment siempre vive dentro de una Activity, y su ciclo de vida depende de la Activity anfitriona, pero no es idéntico a ella.
| Aspecto | Activity | Fragment |
|---|---|---|
| Cantidad de callbacks | 7 (onCreate … onDestroy) | 11 (onAttach … onDetach) |
| Lifecycle separado para View | No | Sí (viewLifecycleOwner) |
| Sobrevive a rotación | No (se destruye) | Sí (ViewModel + Fragment sobreviven) |
| Dependencia del anfitrión | No | Depende del Activity Lifecycle |
| Guardado de estado | onSaveInstanceState | onSaveInstanceState (a nivel de Fragment) |
| Gestión | Sistema | FragmentManager |
La principal diferencia práctica: al rotar la pantalla, Activity se destruye completamente (onDestroy) y se crea de nuevo (onCreate). Fragment durante la rotación pasa por onDestroyView (la View se destruye) → onCreateView (la View se crea de nuevo), pero el propio Fragment y su ViewModel permanecen vivos. Esto hace que Fragment sea un contenedor ideal para la lógica de UI que debe sobrevivir a los cambios de configuración.
Orden de llamadas durante la rotación de pantalla: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity destruida) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.
FragmentManager es la clase central responsable de agregar, eliminar, reemplazar fragments y gestionar sus estados. FragmentManager mantiene la BackStack y garantiza el orden correcto de callbacks durante las transacciones. Cada Activity y cada Fragment anidado tienen su propio FragmentManager.
Operaciones principales de FragmentManager:
BackStack es la pila de transacciones de FragmentManager. Al presionar el botón de retroceso del sistema, la última transacción en BackStack se revierte (popBackStack()). Un Fragment eliminado mediante popBackStack se restaura. Si BackStack está vacío, presionar Atrás finaliza la Activity.
Según Google, el 78% de los problemas con Fragment (duplicación, pantallas vacías, IllegalStateException) están relacionados con el uso incorrecto de FragmentManager. La regla principal: ejecute las transacciones mediante commit() (de forma asíncrona) o commitNow() (de forma síncrona) según el contexto. commit() garantiza el orden correcto en múltiples transacciones.
Fragment admite su propio mecanismo de guardado de estado a través de onSaveInstanceState, que funciona independientemente de Activity. Fragment guarda el estado en un Bundle que se pasa a onCreate y onCreateView durante la restauración.
Cuándo Fragment guarda el estado:
Enfoque moderno: use SavedStateHandle en ViewModel para guardar el estado de Fragment. SavedStateHandle guarda y restaura datos automáticamente al rotar la pantalla y en caso de muerte del proceso, sin necesidad de onSaveInstanceState manual. Google recomienda SavedStateHandle como la forma preferida de guardar el estado de UI en Fragment.
setRetainInstance (obsoleto desde Fragment 1.3): anteriormente Fragment podía conservarse mediante setRetainInstance(true) al rotar la pantalla. Este enfoque ha sido reemplazado por ViewModel + SavedStateHandle, que funcionan de manera más confiable y no requieren configuración especial.
viewLifecycleOwner es un Lifecycle vinculado a la View de Fragment (de onCreateView a onDestroyView). Este es un concepto fundamentalmente importante: las suscripciones a LiveData/Flow realizadas a través de viewLifecycleOwner se cancelan automáticamente cuando la View se destruye (onDestroyView), pero no afectan al propio Fragment.
Diferencia entre viewLifecycleOwner y el lifecycle de Fragment:
Por qué es importante: si se suscribe a LiveData a través del lifecycle de Fragment (this), después de onDestroyView la suscripción permanece activa y LiveData intentará actualizar una View nula, causando NPE. Suscribirse a través de viewLifecycleOwner garantiza que después de onDestroyView no se produzcan actualizaciones de UI.
Regla: en Fragment, use siempre viewLifecycleOwner para suscripciones a LiveData, Flow y corrutinas relacionadas con la UI. Para las corrutinas de ViewModel, use viewModelScope — está vinculado a ViewModel, no a Fragment.
Demuestra la inicialización correcta de UI y la suscripción a LiveData a través de viewLifecycleOwner.
class UserListFragment : Fragment() {
private val viewModel: UserListViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_user_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val button: Button = view.findViewById(R.id.load_button)
button.setOnClickListener { viewModel.loadUsers() }
viewModel.users.observe(viewLifecycleOwner) { users ->
Log.d("UserListFragment", "Actualizando lista: ${users.size} usuarios")
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("UserListFragment", "onDestroyView: View destruida")
}
}
Fragment infla el layout en onCreateView, configura la UI y se suscribe a LiveData en onViewCreated. La suscripción a través de viewLifecycleOwner es un requisito obligatorio para prevenir fugas de memoria. onDestroyView registra la destrucción de la View — confirmación de que Fragment sobrevive a la rotación de pantalla.
Demuestra cómo agregar Fragment a través de FragmentManager en Activity, reemplazo con BackStack y restauración.
class HostActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, HomeFragment())
.addToBackStack(null)
.commit()
}
}
fun openDetail(userId: String) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, DetailFragment.newInstance(userId))
.addToBackStack(null)
.commit()
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
} else {
super.onBackPressed()
}
}
}
class DetailFragment : Fragment() {
companion object {
fun newInstance(userId: String): DetailFragment {
return DetailFragment().apply {
arguments = Bundle().apply { putString("user_id", userId) }
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val userId = arguments?.getString("user_id")
Log.d("DetailFragment", "Cargando detalles del usuario: $userId")
}
}
Activity usa supportFragmentManager para gestionar fragments. La transacción add() con BackStack garantiza que al presionar Atrás se restaure HomeFragment. openDetail() reemplaza el Fragment actual por DetailFragment con argumentos. La comprobación de savedInstanceState == null previene la duplicación de fragments al rotar la pantalla.
Uso de Flow y StateFlow en Fragment con viewLifecycleOwner para actualizaciones reactivas de UI.
class SearchFragment : Fragment() {
private val viewModel: SearchViewModel by viewModels()
private var binding: FragmentSearchBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentSearchBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.searchButton?.setOnClickListener {
viewModel.search(binding?.queryInput?.text.toString())
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.searchResults.collectLatest { results ->
Log.d("SearchFragment", "Resultados de búsqueda: ${results.size}")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
Fragment usa View Binding para acceder a la View. La corrutina viewLifecycleOwner.lifecycleScope.launch se cancela automáticamente cuando la View se destruye. El binding se anula en onDestroyView para prevenir fugas de memoria. StateFlow garantiza la actualización de los datos al recrearse la View.
Preguntas frecuentes
onCreateView crea y devuelve la View raíz de Fragment. onViewCreated se llama inmediatamente después de la creación de la View, garantizando que la View está completamente inicializada y lista para la configuración (findViewById, suscripciones). Google recomienda solo inflar el layout en onCreateView y hacer toda la configuración de UI en onViewCreated.
onDestroy — Fragment se destruye como objeto (ViewModel se limpia, las corrutinas se cancelan). onDetach es el último callback, después del cual Fragment se desvincula de la Activity. Prácticamente todos los recursos deben liberarse en onDestroyView (View) y onDestroy (Fragment). onDetach es para limpiar referencias a la Activity.
Fragment desaparece si no fue agregado a FragmentManager mediante una transacción con preservación en BackStack o si Activity no restaura FragmentManager en onCreate. Solución: agregue Fragment programáticamente a través de supportFragmentManager.beginTransaction().add() en onCreate con la comprobación de savedInstanceState == null.
No. Fragment siempre está vinculado a una Activity a través de FragmentManager. Incluso al rotar la pantalla, Activity se recrea y Fragment se vuelve a vincular a la nueva Activity. No es posible crear un Fragment fuera de una Activity — el constructor de Fragment requiere un constructor vacío para la restauración por parte del sistema.
Los fragments anidados (nested fragments) son Fragments dentro de otro Fragment. Se utilizan para construir pantallas complejas: paneles de pestañas, paneles con fichas, master-detail. Los fragments anidados se gestionan mediante el FragmentManager secundario (childFragmentManager). Google recomienda no superar los 2 niveles de anidamiento para evitar problemas de rendimiento.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también