NullPointerException Zugriff auf Ansichten in onCreate ()

114

Dies ist eine kanonische Frage für ein Problem, das häufig auf StackOverflow veröffentlicht wird.

Ich folge einem Tutorial. Ich habe mit einem Assistenten eine neue Aktivität erstellt. Ich bekomme NullPointerExceptionbeim Versuch , eine Methode zu nennen Views mit erhielt findViewById()in meiner Tätigkeit onCreate().

Aktivität 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>
laalto
quelle

Antworten:

70

Das Lernprogramm ist wahrscheinlich veraltet und versucht, eine aktivitätsbasierte Benutzeroberfläche anstelle der fragmentbasierten Benutzeroberfläche zu erstellen, die vom vom Assistenten generierten Code bevorzugt wird.

Die Ansicht befindet sich im Fragmentlayout ( fragment_main.xml) und nicht im Aktivitätslayout ( activity_main.xml). onCreate()ist zu früh im Lebenszyklus, um es in der Hierarchie der Aktivitätsansicht zu finden, und a nullwird zurückgegeben. Das Aufrufen einer Methode auf nullverursacht die NPE.

Die bevorzugte Lösung besteht darin, den Code in das Fragment zu verschieben onCreateView()und findViewById()das aufgeblasene Fragmentlayout aufzurufen 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;
}

Als Randnotiz wird das Fragmentlayout möglicherweise Teil der Hierarchie der Aktivitätsansicht und kann mit Aktivität erkannt werden, findViewById()jedoch erst, nachdem die Fragmenttransaktion ausgeführt wurde. Ausstehende Fragmenttransaktionen werden super.onStart()nachher ausgeführt onCreate().

laalto
quelle
Der Teil findViewById sollte sich in onActivityCreated befinden.
Zar E Ahmer
@Nepster Es kann sein, muss aber nicht.
Laalto
Manchmal ist die Aktivität noch nicht an ein Fragment gebunden.
Zar E Ahmer
1
@Nepster Und deshalb ruft findViewById()auf rootViewund nicht auf Aktivität.
Laalto
10

Probieren Sie die OnStart()Methode aus und verwenden Sie sie einfach

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

oder Deklarieren Sie eine Ansicht mit der getView().findViewByIdMethode inonStart()

Deklarieren Sie den Klick-Listener in der Ansicht von anyView.setOnClickListener(this);

Tarun Sharma
quelle
Für mich war dies nützlich, weil ich versucht habe, auf eine Geschwisteransicht in onCreateView eines Fragments zuzugreifen, in der das Fragment in XML deklariert wurde. Die Geschwisteransichten waren in onCreateView immer noch null, weil die Eltern das Aufpumpen noch nicht beendet hatten, aber in onStart hatten sie :)
Daniel Wilson
3

Versuchen Sie, Ihre Zugriffsansichten auf die Fragmentmethode onViewCreated zu verschieben, da diese manchmal beim Versuch, auf die Ansichten in der Methode onCreate zuzugreifen, zum Zeitpunkt der resultierenden Nullzeigerausnahme nicht gerendert werden.

 @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();
    }
 }
Sarthak Sharma
quelle
2

Einverstanden ist dies ein typischer Fehler, da die Leute oft nicht wirklich verstehen, wie Fragmente funktionieren, wenn sie anfangen, an der Android-Entwicklung zu arbeiten. Um Verwirrung zu vermeiden, habe ich einen einfachen Beispielcode erstellt, den ich ursprünglich auf Application gepostet habe und der im Android-Emulator gestoppt ist gepostet habe. Er , aber ich habe ihn auch hier gepostet.

Ein Beispiel ist das Folgende:

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>

BeispielFragment:

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>

Und das sollte ein gültiges Beispiel sein. Es zeigt, wie Sie eine Aktivität verwenden können, um ein Fragment anzuzeigen und Ereignisse in diesem Fragment zu behandeln. Und auch, wie man mit der enthaltenen Aktivität kommuniziert.

EpicPandaForce
quelle
1
In diesem Beispiel werden die android-support-v4-Bibliothek für FragmentActivity und der Support-Fragment-Manager verwendet.
EpicPandaForce
1
Ein noch vollständigeres Beispiel finden Sie unter stackoverflow.com/questions/24840509/…
EpicPandaForce
1
Obwohl Sie Ottofür die Kommunikation anstelle von Rückrufen verwenden und Butterknifezum Einfügen von Ansichten verwenden sollten.
EpicPandaForce
2

Die Ansicht "etwas" befindet sich in einem Fragment und nicht in einer Aktivität. Anstatt in einer Aktivität darauf zuzugreifen, müssen Sie in der Fragmentklasse wie darauf zugreifen

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;
}
Shubham Goel
quelle
2

Sie versuchen, auf UI-Elemente in der onCreate()zuzugreifen, aber es ist zu früh, um darauf zuzugreifen, da in Fragmentansichten onCreateView()Methoden erstellt werden können. Die onActivityCreated()Methode ist zuverlässig, um alle Aktionen auf ihnen auszuführen, da die Aktivität in diesem Zustand vollständig geladen ist.

Krishna
quelle
1

Fügen Sie Folgendes in Ihre activity_main.xml ein

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

Da Sie Ihre Ansicht in deklariert haben fragment_main.xml, verschieben Sie den Code, in dem Sie die NPE in der onCreateView()Methode des Fragments erhalten. Dies sollte das Problem lösen.

Rohit Goyal
quelle
0

Im oben angegebenen Code in der Frage gibt es ein Problem: Sie verwenden R.layout.activity_main in der Methode oncreate, aber der Name der XML-Datei lautet "fragment_main.xml". Dies bedeutet, dass Sie versuchen, die Ansicht der Datei fragment_main.xml abzurufen Dies wird nicht angezeigt, sodass eine Nullzeigerausnahme vorliegt. Ändern Sie den Code wie folgt:

@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();
    }
}
Akshay Paliwal
quelle
0

Beachten Sie Folgendes: NullPointerException tritt auf, wenn Sie Ihre Variable deklariert haben und versuchen, ihren Wert abzurufen, bevor Sie ihr einen Wert zuweisen.

Mohan Munisifreddy
quelle
0

Verwenden Sie die onViewCreated () -Methode, wenn Sie Ansichten aus Fragmenten verwenden oder aufrufen.

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

Ich habe die gleiche NullPointerExceptionInitialisierung eines Listeners nach dem Anruf findViewById() onCreate()undonCreateView() Methoden.

Aber wenn ich das benutzt habe, onActivityCreated(Bundle savedInstanceState) {...}funktioniert es. So konnte ich auf die zugreifenGroupView und meinen Listener einstellen.

Ich hoffe es ist hilfreich.

Clebertx
quelle
0

Beliebteste Bibliothek zum Auffinden von Ansichten, die von fast jedem Entwickler verwendet wird.

Buttermesser

Wie ich kann, gibt es genug Antworten, um das Finden von Ansichten mit der richtigen Methodik zu erklären. Wenn Sie jedoch täglich Android-Entwickler und -Code sind, können Sie ein Buttermesser verwenden, das viel Zeit beim Suchen von Ansichten spart und für das Sie keinen Code schreiben müssen. In 2-3 Schritten können Sie Ansichten in Millisekunden finden .

Abhängigkeit in Gradle auf App-Ebene hinzufügen:

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

Plugin für Buttermesser hinzufügen:

File -> Settings -> plugins-> 

Dann suchen Sie nach Android ButterKnife Zelezny und installieren Sie das Plugin und starten Sie Ihr Studio neu und Sie sind fertig.

Gehen Sie jetzt einfach zur Oncreate-Methode Ihrer Aktivität und klicken Sie mit der rechten Maustaste auf Ihren Layoutnamen. Tippen Sie auf die Schaltfläche "Generieren" und wählen Sie die Option "Buttermesser-Injektion". Ihre Ansichtsreferenzen werden automatisch wie unten erwähnt erstellt:

    @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;
Rishabh Saxena
quelle