NullPointerException no fragmento Kotlin: como vencer e não enlouquecer

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: "Fiz tudo conforme o tutorial, mas o aplicativo trava!"

\n

Se você está começando no desenvolvimento Android com Kotlin, provavelmente já passou por isso. Você escreve o código seguindo um tutorial, executa o aplicativo… e crash. Nos logs — o famoso java.lang.NullPointerException (ou seu equivalente em Kotlin). E a mensagem: "Cannot read field… because the view is null".

\n

Essa é uma dor real que gerou milhares de visualizações no Stack Overflow. Hoje vamos analisá-la de uma vez por todas. Por que ocorre o NullPointerException ao acessar View no Fragment em Kotlin? E, principalmente, como corrigir isso para você dormir tranquilo.

\n

Vamos lá!

\n\n

Por que o erro ocorre? A raiz do problema — Lifecycle

\n

A principal razão pela qual iniciantes recebem NullPointerException no Fragment Kotlin é a falta de compreensão do ciclo de vida do fragment. Na Activity é simples: onCreate — e pronto. No Fragment é mais complicado.

\n

O fragment passa por várias etapas:

\n
    \n
  • onCreateView() — aqui o layout é inflado (criado).
  • \n
  • onViewCreated() — aqui a View já existe com certeza.
  • \n
  • onDestroyView() — a View é destruída (por exemplo, ao girar a tela).
  • \n
\n

O erro mais comum é tentar acessar a View antes de o fragment criar seu layout. Por exemplo, no construtor ou no onCreate() do fragment. Nesse momento, view é igual a null — daí o crash.

\n

A segunda causa é o vazamento de referências. Você salvou uma referência à View em uma variável, depois o fragment foi recriado, e a referência antiga leva a lugar nenhum.

\n\n

Exemplo típico: como o problema aparece no código

\n

Imagine que você tem um fragment simples com um 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        // ERRO! Aqui a View ainda não existe\n        myTextView = requireView().findViewById(R.id.my_text_view)\n        myTextView.text = "Olá!"\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

Esse código vai falhar com NullPointerException, porque requireView() no onCreate() retorna null. A View ainda não foi criada!

\n\n

3 formas funcionais de corrigir o erro

\n

Vamos ver três abordagens que resolvem garantidamente o problema de acesso à View no Fragment.

\n\n

Forma 1: Mover o código para onViewCreated()

\n

A maneira mais simples e correta é esperar o momento em que a View existe com certeza. O método onViewCreated() é chamado imediatamente após a criação do 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        // Agora a view definitivamente não é null!\n        myTextView = view.findViewById(R.id.my_text_view)\n        myTextView.text = "Tudo funcionando!"\n    }\n}
\n

Vantagens: simples, claro, funciona sempre.
\nDesvantagens: é preciso lembrar do lateinit var e não esquecer de anular as referências em onDestroyView() (caso contrário, pode haver vazamento de memória).

\n\n

Forma 2: Usar View Binding (recomendado)

\n

Blogs

Book Recommendations