NullPointerException durante l'accesso alle viste in onCreate ()


114

Questa è una domanda canonica per un problema pubblicato di frequente su StackOverflow.

Sto seguendo un tutorial. Ho creato una nuova attività utilizzando una procedura guidata. Ottengo NullPointerExceptionquando tento di chiamare un metodo su Views ottenuto con findViewById()nella mia attività onCreate().

Attività 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>

Risposte:


70

Il tutorial è probabilmente obsoleto e tenta di creare un'interfaccia utente basata su attività invece dell'interfaccia utente basata su frammenti preferita dal codice generato dalla procedura guidata.

La vista è nel layout del frammento ( fragment_main.xml) e non nel layout dell'attività ( activity_main.xml). onCreate()è troppo presto nel ciclo di vita per trovarlo nella gerarchia della visualizzazione attività e nullviene restituito un. Invocare un metodo su nullcausa l'NPE.

La soluzione preferita è spostare il codice nel frammento onCreateView(), richiamando findViewById()il layout del frammento gonfiato 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;
}

Come nota a margine, il layout del frammento finirà per far parte della gerarchia della visualizzazione dell'attività e sarà individuabile con l'attività findViewById()ma solo dopo che la transazione del frammento sarà stata eseguita. Le transazioni di frammento in sospeso vengono eseguite in super.onStart()after onCreate().


La parte findViewById dovrebbe essere in onActivityCreated.
Zar E Ahmer

@Nepster Può essere, ma non è necessario.
laalto

A volte l'attività non è ancora collegata al frammento.
Zar E Ahmer

1
@Nepster Ed è per questo che chiedono findViewById()su rootViewe non sull'attività.
laalto

10

Prova il OnStart()metodo e usalo

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

o Dichiarare qualsiasi visualizzazione utilizzando il getView().findViewByIdmetodo inonStart()

Dichiara il listener di clic sulla visualizzazione di anyView.setOnClickListener(this);


Per me questo è stato utile perché stavo cercando di accedere a una vista di pari livello all'interno di onCreateView di un frammento, dove il frammento è stato dichiarato in xml. Le visualizzazioni dei fratelli erano ancora nulle in onCreateView perché il genitore non aveva finito di gonfiare, ma in onStart lo avevano :)
Daniel Wilson

3

Prova a spostare le tue viste di accesso al metodo di frammento onViewCreated perché a volte, quando provi ad accedere alle viste nel metodo onCreate, non viene eseguito il rendering al momento con conseguente eccezione del puntatore nullo.

 @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

D'accordo, questo è un errore tipico perché le persone spesso non capiscono davvero come funzionano i frammenti quando iniziano a lavorare allo sviluppo di Android. Per alleviare la confusione, ho creato un semplice codice di esempio che ho originariamente pubblicato su L' applicazione viene interrotta nell'emulatore Android , ma l'ho pubblicato anche qui.

Un esempio è il seguente:

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 questo dovrebbe essere un esempio valido, mostra come puoi utilizzare un'attività per visualizzare un frammento e gestire gli eventi in quel frammento. E anche come comunicare con l'Attività contenitore.


1
Questo esempio usa la libreria android-support-v4 per FragmentActivity e il gestore dei frammenti di supporto.
EpicPandaForce

1
un esempio ancora più completo è disponibile presso stackoverflow.com/questions/24840509/...
EpicPandaForce

1
Anche se dovresti usare Ottoper la comunicazione invece di callback e usare Butterknifeper iniettare visualizzazioni.
EpicPandaForce

2

La vista "qualcosa" è in frammento e non in attività, quindi invece di accedervi in ​​attività devi accedervi nella classe di frammento come

In 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

Stai tentando di accedere agli elementi dell'interfaccia utente in onCreate()ma, è troppo presto per accedervi, poiché nelle viste frammento possono essere create in onCreateView()metodo. E il onActivityCreated()metodo è affidabile per gestire qualsiasi azione su di essi, poiché l'attività è completamente caricata in questo stato.


1

Aggiungi quanto segue nel tuo 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

Dal momento che hai dichiarato la tua vista in fragment_main.xml, sposta quella parte di codice in cui ottieni l'NPE nel onCreateView()metodo del frammento. Questo dovrebbe risolvere il problema.


0

nel codice pubblicato sopra nella domanda c'è un problema: stai usando R.layout.activity_main nel metodo oncreate, ma il nome del file xml è "fragment_main.xml", significa che stai cercando di ottenere la visualizzazione del file fragment_main.xml che non viene mostrato quindi dà un'eccezione al puntatore nullo. cambia il codice come:

@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

Devi ricordare che cosa importante è: NullPointerException si verifica quando hai dichiarato la tua variabile e provi a recuperarne il valore prima di assegnargli un valore.


0

Utilizzare il metodo onViewCreated () ogni volta che si utilizzano o si richiamano visualizzazioni da frammenti.

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

0

Ho lo stesso NullPointerExceptioninizializzare un listener dopo la chiamata findViewById() onCreate()e i onCreateView()metodi.

Ma quando l'ho usato onActivityCreated(Bundle savedInstanceState) {...}funziona. Quindi, potrei accedere a GroupViewe impostare il mio ascoltatore.

Spero che sia utile


0

La libreria più popolare per la ricerca di visualizzazioni utilizzata da quasi tutti gli sviluppatori.

Coltello da burro

Per quanto posso, ci sono risposte sufficienti per spiegare come trovare punti di vista con una metodologia adeguata. Ma se sei uno sviluppatore Android e codifichi frequentemente su base giornaliera, puoi utilizzare il coltello da burro che consente di risparmiare molto tempo nella ricerca delle visualizzazioni e non hai codice di scrittura per esso, Con in 2-3 passaggi puoi trovare le visualizzazioni in millisecondi .

Aggiungi dipendenza in gradle a livello di app:

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

Aggiungi plugin per coltello da burro:

File -> Settings -> plugins-> 

Quindi cerca Android ButterKnife Zelezny, installa il plug-in e riavvia il tuo studio e il gioco è fatto.

Ora vai al metodo Oncreate della tua attività e fai clic con il pulsante destro del mouse sul tuo layout_name e tocca il pulsante di generazione e seleziona l'opzione di iniezione Butterknife ei tuoi riferimenti alle visualizzazioni verranno creati automaticamente come indicato di seguito:

    @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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.