NullPointerException acessando visualizações em onCreate ()


114

Esta é uma pergunta canônica para um problema frequentemente postado no StackOverflow.

Estou seguindo um tutorial. Criei uma nova atividade usando um assistente. Eu recebo NullPointerExceptionao tentar chamar um método em Views obtidos com findViewById()em minha atividade onCreate().

Atividade onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

Layout XML ( fragment_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="packagename.MainActivity$PlaceholderFragment" >

    <View
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/something" />

</RelativeLayout>

Respostas:


70

O tutorial provavelmente está desatualizado, tentando criar uma IU baseada em atividades em vez da IU baseada em fragmentos preferida pelo código gerado pelo assistente.

A visualização está no layout do fragmento ( fragment_main.xml) e não no layout da atividade ( activity_main.xml). onCreate()está muito no início do ciclo de vida para localizá-lo na hierarquia de visualização de atividades e a nullé retornado. Invocar um método em nullcausa o NPE.

A solução preferida é mover o código para o fragmento onCreateView(), chamando findViewById()o layout do fragmento inflado rootView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
  View rootView = inflater.inflate(R.layout.fragment_main, container,
      false);

  View something = rootView.findViewById(R.id.something); // not activity findViewById()
  something.setOnClickListener(new View.OnClickListener() { ... });

  return rootView;
}

Como uma observação lateral, o layout do fragmento acabará por fazer parte da hierarquia de visualização da atividade e poderá ser descoberto com a atividade, findViewById()mas somente depois que a transação do fragmento for executada. As transações de fragmentos pendentes são executadas super.onStart()depois onCreate().


A parte findViewById deve estar em onActivityCreated.
Zar E Ahmer

@Nepster Pode ser, mas não precisa.
laalto

Às vezes, a atividade ainda não está anexada ao fragmento.
Zar E Ahmer

1
@Nepster e é por isso que chamam findViewById()sobre rootViewe não sobre a atividade.
laalto

10

Experimente o OnStart()método e apenas use

View view = getView().findViewById(R.id.something);

ou Declare qualquer View usando o getView().findViewByIdmétodo emonStart()

Declarar ouvinte de clique em exibição por anyView.setOnClickListener(this);


Para mim, isso foi útil porque eu estava tentando acessar uma visualização irmã dentro do onCreateView de um fragmento, onde o fragmento foi declarado em xml. As visualizações irmãs ainda eram nulas em onCreateView porque o pai não tinha terminado de aumentar, mas em onStart elas tinham :)
Daniel Wilson

3

Tente mudar suas visualizações de acesso para o método onViewCreated de fragmento porque às vezes, quando você tenta acessar as visualizações no método onCreate, elas não são renderizadas no momento, resultando em exceção de ponteiro nulo.

 @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
     View something = findViewById(R.id.something);
     something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

     if (savedInstanceState == null) {
           getSupportFragmentManager().beginTransaction()
            .add(R.id.container, new PlaceholderFragment()).commit();
    }
 }

2

Concordo, esse é um erro típico porque as pessoas geralmente não entendem como os Fragments funcionam quando começam a trabalhar no desenvolvimento do Android. Para aliviar a confusão, criei um código de exemplo simples que publiquei originalmente em Application is Stop in android emulator , mas também o postei aqui.

Um exemplo é o seguinte:

public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
{
    @Override
    public void onCreate(Bundle saveInstanceState)
    {
        super.onCreate(saveInstanceState);
        this.setContentView(R.layout.activity_container);
        if (saveInstanceState == null)
        {               
             getSupportFragmentManager().beginTransaction()
                .add(R.id.activity_container_container, new ExampleFragment())
                .addToBackStack(null)
             .commit();
        }
        getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
        {
            public void onBackStackChanged()
            {
                int backCount = getSupportFragmentManager().getBackStackEntryCount();
                if (backCount == 0)
                {
                    finish();
                }
            }
        });
    }

    @Override
    public void exampleFragmentCallback()
    {
        Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
    }
}

activity_container.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/activity_container_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

ExampleFragment:

public class ExampleFragment extends Fragment implements View.OnClickListener
{
    public static interface Callback
    {
        void exampleFragmentCallback();
    }

    private Button btnOne;
    private Button btnTwo;
    private Button btnThree;

    private Callback callback;

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        try
        {
            this.callback = (Callback) activity;
        }
        catch (ClassCastException e)
        {
            Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
            throw e;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_example, container, false);

        btnOne = (Button) rootView.findViewById(R.id.example_button_one);
        btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
        btnThree = (Button) rootView.findViewById(R.id.example_button_three);

        btnOne.setOnClickListener(this);
        btnTwo.setOnClickListener(this);
        btnThree.setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v)
    {
        if (btnOne == v)
        {
            Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
        }
        else if (btnTwo == v)
        {
            Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
        }
        else if (btnThree == v)
        {
            callback.exampleFragmentCallback();
        }
    }
}

fragment_example.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <Button
            android:id="@+id/example_button_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            android:text="@string/hello" 
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"/>

        <Button
            android:id="@+id/example_button_two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/example_button_one"
            android:layout_alignRight="@+id/example_button_one"
            android:layout_below="@+id/example_button_one"
            android:layout_marginTop="30dp"
            android:text="@string/hello" />

        <Button
            android:id="@+id/example_button_three"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/example_button_two"
            android:layout_alignRight="@+id/example_button_two"
            android:layout_below="@+id/example_button_two"
            android:layout_marginTop="30dp"
            android:text="@string/hello" />

</RelativeLayout>

E esse deve ser um exemplo válido, ele mostra como você pode usar uma Activity para exibir um Fragment e manipular eventos nesse Fragment. E também como se comunicar com a atividade contida.


1
Este exemplo usa a biblioteca android-support-v4 para FragmentActivity e o gerenciador de fragmentos de suporte.
EpicPandaForce

1
um exemplo ainda mais completo está disponível em stackoverflow.com/questions/24840509/…
EpicPandaForce

1
Embora você deva usar Ottopara comunicação em vez de callbacks, e use Butterknifepara injetar visualizações.
EpicPandaForce de

2

A visão "algo" está em fragmento e não em atividade, portanto, em vez de acessá-la em atividade, você deve acessá-la na classe de fragmento como

Em PlaceholderFragment.class

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container,
  false);

View something = root .findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... });

return root;
}

2

Você está tentando acessar os elementos da interface do usuário no onCreate(), mas é muito cedo para acessá-los, uma vez que as visualizações de fragmento podem ser criadas no onCreateView()método. E o onActivityCreated()método é confiável para lidar com qualquer ação neles, uma vez que a atividade está totalmente carregada neste estado.


1

Adicione o seguinte em seu activity_main.xml

<fragment
    android:id="@+id/myFragment"
    android:name="packagename.MainActivity$PlaceholderFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
</fragment>

0

Já que você declarou sua View no fragment_main.xml, mova aquele trecho de código de onde você obteve o NPE no onCreateView()método do fragmento. Isso deve resolver o problema.


0

no código postado acima na questão, há um problema: você está usando R.layout.activity_main no método oncreate, mas o nome dos arquivos xml é "fragment_main.xml", significa que você está tentando obter a visualização do arquivo fragment_main.xml que não está sendo mostrado, portanto, fornece exceção de ponteiro nulo. mude o código como:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_main);// your xml layout ,where the views are

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

0

Você tem que lembrar que o que é importante é: NullPointerException ocorre quando você declara sua variável e tenta recuperar seu valor antes de atribuir valor a ela.


0

Use o método onViewCreated () sempre que usar ou chamar visualizações de fragmentos.

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
      View v = view.findViewById(R.id.whatever)
}

0

Eu tenho o mesmo NullPointerExceptioninicializando um ouvinte depois de chamar findViewById() onCreate()eonCreateView() métodos.

Mas quando uso o, onActivityCreated(Bundle savedInstanceState) {...}ele funciona. Então, eu poderia acessar oGroupView e definir meu ouvinte.

Espero que seja útil.


0

Biblioteca mais popular para encontrar visualizações que é usada por quase todos os desenvolvedores.

Faca de manteiga

Como posso, há respostas suficientes explicando como encontrar pontos de vista com a metodologia adequada. Mas se você é um desenvolvedor Android e codifica frequentemente diariamente, então você pode usar uma faca de manteiga, o que economiza muito tempo em encontrar visualizações e você não precisa escrever código para isso. Em 2-3 etapas, você pode encontrar visualizações em milissegundos .

Adicionar dependência no gradle de nível de aplicativo:

implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

Adicionar plugin para faca de manteiga:

File -> Settings -> plugins-> 

Em seguida, procure por Android ButterKnife Zelezny e instale o plugin e reinicie o seu estúdio e pronto.

Agora basta ir ao método Oncreate de sua atividade e clicar com o botão direito em seu layout_name e tocar no botão gerar e selecionar a opção de injeção de butterknife e suas referências de visualizações serão criadas automaticamente como a menção abaixo:

    @BindView(R.id.rv_featured_artist)
    ViewPager rvFeaturedArtist;
    @BindView(R.id.indicator)
    PageIndicator indicator;
    @BindView(R.id.rv_artist)
    RecyclerView rvArtist;
    @BindView(R.id.nsv)
    NestedScrollingView nsv;
    @BindView(R.id.btn_filter)
    Button btnFilter;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.