NullPointerException en fragmento de Kotlin: cómo vencerlo y no volverse loco

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: «¡Hice todo según el tutorial, pero la aplicación se cierra!»

\n

Si recién estás comenzando tu camino en el desarrollo de Android con Kotlin, seguramente ya te has encontrado con este momento. Escribes código siguiendo un tutorial, ejecutas la aplicación… y crash. En los registros aparece el famoso java.lang.NullPointerException (o su equivalente en Kotlin). Y el mensaje: «Cannot read field… because the view is null».

\n

Este es un dolor real que ha acumulado miles de visitas en Stack Overflow. Hoy lo analizaremos de una vez por todas. ¿Por qué ocurre el NullPointerException al acceder a View en un Fragmento en Kotlin? Y, lo más importante, cómo solucionarlo para que puedas dormir tranquilo.

\n

¡Allá vamos!

\n\n

¿Por qué ocurre el error? La raíz del mal: el Lifecycle

\n

La razón principal por la que los principiantes obtienen un NullPointerException en un Fragmento de Kotlin es la falta de comprensión del ciclo de vida del fragmento. En una Activity es simple: onCreate y listo. En un Fragmento es más complicado.

\n

El fragmento pasa por varias etapas:

\n
    \n
  • onCreateView() — aquí se infla (crea) el layout.
  • \n
  • onViewCreated() — aquí la View ya existe con certeza.
  • \n
  • onDestroyView() — la View se destruye (por ejemplo, al rotar la pantalla).
  • \n
\n

El error más común es intentar acceder a la View antes de que el fragmento haya creado su layout. Por ejemplo, en el constructor o en onCreate() del fragmento. En ese momento, view es igual a null — de ahí el crash.

\n

La segunda razón es la fuga de referencias. Guardaste una referencia a la View en una variable, luego el fragmento se recrea y la referencia antigua no lleva a ninguna parte.

\n\n

Ejemplo típico: cómo se ve el problema en el código

\n

Imagina que tienes un fragmento simple con un campo de texto:

\n
class MyFragment : Fragment() {\n\n    private lateinit var myTextView: TextView\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        // ¡ERROR! Aquí la View aún no existe\n        myTextView = requireView().findViewById(R.id.my_text_view)\n        myTextView.text = "¡Hola!"\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        return inflater.inflate(R.layout.fragment_my, container, false)\n    }\n}
\n

Este código fallará con un NullPointerException, porque requireView() en onCreate() devuelve null. ¡La View aún no ha sido creada!

\n\n

3 formas prácticas de solucionar el error

\n

Veamos tres enfoques que resuelven garantizadamente el problema del acceso a View en un Fragmento.

\n\n

Forma 1: Mover el código a onViewCreated()

\n

La forma más simple y correcta es esperar al momento en que la View exista con certeza. El método onViewCreated() se llama inmediatamente después de crear el layout.

\n
class MyFragment : Fragment() {\n\n    private lateinit var myTextView: TextView\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        return inflater.inflate(R.layout.fragment_my, container, false)\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        // ¡Ahora view definitivamente no es null!\n        myTextView = view.findViewById(R.id.my_text_view)\n        myTextView.text = "¡Todo funciona!"\n    }\n}
\n

Ventajas: simple, claro, funciona siempre.
\nDesventajas: hay que recordar usar lateinit var y no olvidar anular las referencias en onDestroyView() (de lo contrario, puede haber una fuga de memoria).

\n\n

Forma 2: Usar View Binding (recomendado)

\n

Blogs

Book Recommendations