findViewByID gibt null zurück

251

Zuallererst: Ja, ich habe alle anderen Themen zu diesem Thema gelesen. Und nicht nur die von dieser Seite ... (Sie sehen, ich bin ein wenig frustriert)

Die meisten von ihnen haben den Rat, sie android:idnicht nur idin der XML-Datei zu verwenden. Ich tat.

Von anderen habe ich gelernt, dass View.findViewByIddas anders funktioniert als Activity.findViewById. Ich habe auch damit umgegangen.

In meinem location_layout.xmlbenutze ich:

<FrameLayout .... >
    <some.package.MyCustomView ... />

    <LinearLayout ... >
        <TextView ...
            android:id="@+id/txtLat" />
        ...
    </LinearLayout>
</FrameLayout>

In meiner Tätigkeit mache ich:

...
setContentView( R.layout.location_layout );

und in meiner benutzerdefinierten Ansichtsklasse:

... 
TextView tv = (TextView) findViewById( R.id.txtLat );

was zurückkehrt null. Dabei funktioniert meine Aktivität einwandfrei. So ist es vielleicht wegen der Activity.findViewByIdund View.findViewByIdUnterschiede. Also habe ich den Kontext, der an den Konstruktor der Zollansicht übergeben wurde, lokal gespeichert und versucht:

...
TextView tv = (TextView) ((Activity) context).findViewById( R.id.txtLat );

was auch zurückkehrte null.

Dann habe ich meine benutzerdefinierte Ansicht geändert, um sie ViewGroupstattdessen zu erweitern, Viewund die so geändert location_layout.xml, dass TextViewsie ein direktes untergeordnetes Element meiner benutzerdefinierten Ansicht ist, sodass die Ansicht View.findViewByIdwie angenommen funktionieren soll. Überraschung: Es hat nichts gelöst.

Also, was zum Teufel mache ich falsch?

Ich freue mich über Kommentare.

Thomas
quelle
6
Dies kann auftreten, wenn das Projekt ebenfalls beschädigt ist. Ich habe es behoben, indem ich das Projekt
gereinigt habe
1
falsche Kontextansicht bestanden danke
izzy
1
@ Pacerier danke. das hat mein Problem gelöst. Ich
Artiom
@ Pacerier "Clean project" hat auch mein Problem gelöst. Es scheint, dass Dropbox das Projekt beschädigt hat.
Kohki Mametani

Antworten:

271

was null zurückgibt

Möglicherweise, weil Sie es zu früh anrufen. Warten Sie bis onFinishInflate(). Hier ist ein Beispielprojekt, das zeigt, wie ein Benutzer Viewauf seine Inhalte zugreift.

CommonsWare
quelle
67
OH MEIN GOTT! Ich kann nicht glauben, dass ich Tage mit etwas so Trivialem verbringe. Ich habe setContentView () über den Aufruf findViewById () verschoben, und das hat den Trick nicht getan. Vielen Dank!
Agentcurry
2
@ CommonsWare es das richtige Projekt? Ich sehe onFinishInflate nirgendwo in github.com/commonsguy/cw-advandroid/tree/master/Animation/…
likejudo
1
@likejiujitsu: Das könnte 2010 gewesen sein. Ich habe den Link zu einem neueren Projekt aktualisiert, das hat onFinishInflate().
CommonsWare
3
Ich habe mein setContentView vor findViewById aufgerufen und es ist immer noch null. Ich beziehe mich auf einen EditText
Neon
1
Verlinken Sie
145

Möglicherweise rufen Sie an, findViewByIdbevor Sie anrufen setContentView? Wenn dies der Fall ist, rufen Sie findViewById NACH dem Anruf ansetContentView

Bayram Boyraz
quelle
1
So ein einfacher Fehler, aber leider hatte ich das getan. Der Debugger nützt nichts, da er besagt, dass der Fehler in meiner neuen Absichtszeile nicht in der tatsächlichen neuen Aktivität war, die ich aufgerufen habe. Vielen Dank!
Edude05
6
Eigentlich hatte ich diesen Fehler, weil ich setContentView aufgerufen habe und auf die falsche Ansicht zeigte ... leider fängt der Compiler diese Art von Fehler nicht ab.
HeatfanJohn
Ja, ich habe setContentView versehentlich gelöscht und nicht verstanden, warum mein Programm zu zerquetschen begann.
Ronen Festinger
100

Stellen Sie sicher, dass Sie nicht mehrere Versionen Ihres Layouts für unterschiedliche Bildschirmdichten haben. Ich bin einmal auf dieses Problem gestoßen, als ich einem vorhandenen Layout eine neue ID hinzugefügt habe, habe aber vergessen, die HDPI-Version zu aktualisieren. Wenn Sie vergessen, alle Versionen der Layoutdatei zu aktualisieren, funktioniert dies für einige Bildschirmdichten, für andere jedoch nicht.

Joe
quelle
8
VIELEN DANK! Das war's. (In meinem Fall habe ich mehrere Versionen für verschiedene Android-Versionen). Ich vergesse es die ganze Zeit, obwohl ich oben und unten in jeder Layoutdatei einen gigantischen Kommentar eingefügt habe. Ich wünschte, der Compiler würde in diesem Fall einen Fehler oder eine große Warnung machen.
Tiktak
Ding ding ding, vielen Dank! Beugte mein Gehirn über dieses lol
Zach
21

FindViewById kann null sein, wenn Sie in einer benutzerdefinierten Ansicht den falschen Superkonstruktor aufrufen. Das ID-Tag ist Teil von attrs. Wenn Sie also attrs ignorieren, löschen Sie die ID.

Das wäre falsch

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context);
}

Das ist richtig

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}
repkap11
quelle
1
Vielen Dank, Sir! Ich bin so nachlässig, dass ich nur daran gezweifelt habe, dass etwas mit meiner IDE nicht stimmt. Wie glücklich, Ihre Antwort zu treffen.
EffectiveMatrix
Ich habe diesen Fehler gemacht, als ich meine benutzerdefinierte Ansicht erstellt habe. Danke, repkap11.
Andrew F.
15

In meinem Fall hatte ich 2 Aktivitäten in meinem Projekt main.xmlund main2.xml. Von Anfang an main2war eine Kopie main, und alles funktionierte gut, bis ich neu hinzugefügt TextViewzu main2, so dass die R.id.textview1für den Rest der App zur Verfügung stand. Dann habe ich versucht, es durch Standardaufrufe abzurufen:

TextView tv = (TextView) findViewById( R.id.textview1 );

und es war immer null. Es stellte sich heraus, dass onCreateich im Konstruktor nicht instanziierte main2, sondern den anderen. Ich hatte:

setContentView(R.layout.main);

anstatt

setContentView(R.layout.main2);

Ich bemerkte dies, nachdem ich hier auf der Website angekommen war.

infografnet
quelle
14

Neben den an anderer Stelle erwähnten klassischen Ursachen:

  • Stellen Sie sicher, dass Sie zuvor angerufen setContentView()habenfindViewById()
  • Stellen Sie sicher, dass das idgewünschte Element in der Ansicht oder dem Layout enthalten ist, die Sie angegeben habensetContentView()
  • Stellen Sie sicher, dass das idnicht versehentlich in verschiedenen Layouts dupliziert wird

Ich habe eine für benutzerdefinierte Ansichten in Standardlayouts gefunden, die gegen die Dokumentation verstößt:

Theoretisch können Sie eine benutzerdefinierte Ansicht erstellen und einem Layout hinzufügen ( siehe hier ). Ich habe jedoch festgestellt, dass in solchen Situationen das idAttribut manchmal für alle Ansichten im Layout mit Ausnahme der benutzerdefinierten Ansichten funktioniert. Die Lösung, die ich benutze, ist:

  1. Ersetzen Sie jede benutzerdefinierte Ansicht durch eine FrameLayoutmit denselben Layout-Eigenschaften, die die benutzerdefinierte Ansicht haben soll. idSagen Sie es angemessen , sagen wir frame_for_custom_view.
  2. In onCreate:

    setContentView(R.layout.my_layout);
    FrameView fv = findViewById(R.id.frame_for_custom_layout);
    MyCustomView cv = new MyCustomView(context);
    fv.addView(cv);

    Dadurch wird die benutzerdefinierte Ansicht in den Rahmen eingefügt.

Neil Townsend
quelle
Dies hat mir geholfen: "Stellen Sie sicher, dass die gewünschte ID in der Ansicht oder dem Layout enthalten ist, die Sie setContentView () gegeben haben." Was tun, wenn es sich jedoch um eine Unteransicht handelt? Versucht, die übergeordnete Ansicht zu erhalten, dann tun Sie parentView.findById (), aber es gibt immer noch null zurück
NaturalBornCamper
@naturalborncamper Wenn Sie eine separate Frage mit Beispielcode posten, werde ich sie mir ansehen.
Neil Townsend
Vielen Dank, Neil, ich habe bereits gepostet und jemand hat einen besseren Weg aufgezeigt
NaturalBornCamper
9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }
Jonathan
quelle
6

Eine Antwort für diejenigen, die ExpandableListView verwenden und diese Frage anhand des Titels beantworten.

Ich hatte diesen Fehler beim Versuch, mit TextViews in meinen untergeordneten und Gruppenansichten als Teil einer ExpandableListView-Implementierung zu arbeiten.

Sie können in Ihren Implementierungen der Methoden getChildView () und getGroupView () Folgendes verwenden.

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_layout, null);
        }

Ich habe das hier gefunden .

Josh Metcalfe
quelle
5

Ich bin ziemlich neu in Android / Eclipse, aus Versehen habe ich activity_main.xmlstattdessen das UI-Zeug hinzugefügt fragment_main.xml. Ich habe einige Stunden gebraucht, um das herauszufinden ...

lama12345
quelle
5

FWIW, ich sehe nicht, dass irgendjemand dies auf die gleiche Weise gelöst hat, wie ich es brauchte. Keine Beschwerden zur Kompilierungszeit, aber ich bekam zur Laufzeit eine Nullansicht und rief die Dinge in der richtigen Reihenfolge auf. Das heißt, findViewById () nach setContentView (). Das Problem stellte sich heraus, dass meine Ansicht in content_main.xml definiert ist, aber in meiner activity_main.xml fehlte mir diese eine Anweisung:

<include layout="@layout/content_main" />

Als ich das zu activity_main.xml hinzufügte, kein NullPointer mehr.

Ferris
quelle
Das Problem beim Einfügen eines Fragments durch Kopieren besteht darin, dass Sie manchmal vergessen, einige Dinge zu ändern. Dies ist das richtige Layout, um eines davon aufzublasen. Vielen Dank!
Pablo Quemé
3

Ich hatte das gleiche Problem. Ich habe eine Bibliothek eines Drittanbieters verwendet, mit der Sie den Adapter für eine GridView überschreiben und für jede GridView-Zelle ein eigenes Layout angeben können.

Endlich wurde mir klar, was los war. Eclipse verwendete weiterhin die Layout-XML-Datei der Bibliothek für jede Zelle in GridView, obwohl dies keinen Hinweis darauf gab. In meinem benutzerdefinierten Adapter wurde angezeigt, dass die XML-Ressource aus meinem eigenen Projekt verwendet wurde, obwohl dies zur Laufzeit nicht der Fall war.

Ich habe also sichergestellt, dass sich meine benutzerdefinierten XML-Layouts und -IDs von denen unterscheiden, die sich noch in der Bibliothek befinden. Ich habe das Projekt bereinigt und dann die richtigen benutzerdefinierten Layouts in meinem Projekt gelesen.

Kurz gesagt, seien Sie vorsichtig, wenn Sie den Adapter einer Drittanbieter-Bibliothek überschreiben und Ihre eigene Layout-XML für den zu verwendenden Adapter angeben. Wenn Ihr Layout in Ihrem Projekt denselben Dateinamen wie das in der Bibliothek hat, tritt möglicherweise ein wirklich schwer zu findender Fehler auf!

JDJ
quelle
3

In meinem speziellen Fall habe ich versucht, einer ListView eine Fußzeile hinzuzufügen. Der folgende Aufruf in onCreate () gab null zurück.

TextView footerView = (TextView) placesListView.findViewById(R.id.footer);

Wenn Sie dies ändern, um die Fußzeilenansicht aufzublähen, anstatt sie anhand der ID zu finden, wurde dieses Problem behoben.

View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer_view, null, false);
Matt
quelle
2

In meinem Fall habe ich ExpandableListView verwendet und festgelegt android:transcriptMode="normal". Dies führte dazu, dass nur wenige Kinder in einer erweiterbaren Gruppe verschwanden und ich immer eine NULL-Ausnahme bekam, wenn ich die Liste scrollte.

Jeevan
quelle
2

Für mich hatte ich zwei XML-Layouts für dieselbe Aktivität - eines im Hochformat und eines im Querformat. Natürlich hatte ich die ID eines Objekts in der Querformat-XML geändert, aber vergessen, dieselbe Änderung in der Hochformatversion vorzunehmen. Stellen Sie sicher, dass Sie, wenn Sie eine ändern, dasselbe mit der anderen XML tun. Andernfalls wird keine Fehlermeldung angezeigt, bis Sie sie ausführen / debuggen und die ID, die Sie nicht geändert haben, nicht gefunden wird. Oh dumme Fehler, warum musst du mich so bestrafen?

ColossalChris
quelle
2

Legen Sie den Aktivitätsinhalt aus einer Layoutressource fest. dh setContentView(R.layout.basicXml);

Ajay Takur
quelle
2

Zusätzlich zu den oben genannten Lösungen stellen Sie sicher, dass der
tools:context=".TakeMultipleImages" Wert im Layout derselbe Wert in der Datei mainfest.xml ist:
android:name=".TakeMultipleImages"für dasselbe Aktivitätselement. Es tritt auf, wenn Sie mit Kopieren und Einfügen neue Aktivitäten erstellen

user2982286
quelle
2

Ich habe das gleiche Problem, aber ich denke, es lohnt sich, es mit euch zu teilen. Wenn Sie ViewById in einem benutzerdefinierten Layout finden müssen, zum Beispiel:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

Sie können die Ansicht im Konstruktor nicht erhalten. Sie sollten findViewById aufrufen, nachdem die Ansicht aufgeblasen wurde. Dies ist eine Methode, die Sie überschreiben könnenonFinishInflate

Shaw
quelle
2

Ich wollte nur meinen speziellen Fall hier reinwerfen. Könnte jemandem auf der ganzen Linie helfen.

Ich habe die Direktive in meinem Android UI XML wie folgt verwendet:

Übergeordnete Ansicht:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:visibility="gone" />

Untergeordnete Ansicht (retry_button):

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/retry"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

.findViewById (R.id.retry) würde immer null zurückgeben. Wenn ich jedoch die ID aus der untergeordneten Ansicht in das Include-Tag verschoben habe, hat sie funktioniert.

Feste Eltern:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:id="@+id/retry"
        android:visibility="gone" />

Festes Kind:

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">
John D.
quelle
2

Mein Fall ist keiner wie oben, keine Lösungen haben funktioniert. Ich gehe davon aus, dass meine Ansicht zu tief in der Layouthierarchie lag. Ich habe es eine Ebene nach oben verschoben und es war nicht mehr null.

Deividas Strioga
quelle
Ich habe das gleiche Problem, eine Stufe höher kann auch gefunden werden. Das ist ziemlich ärgerlich und ich würde gerne wissen, warum es passiert, da ich mein Menü nicht so machen kann, wie ich es möchte
NaturalBornCamper
Nun, tiefe Layout-Hierarchien sind Anti-Muster, fast immer gibt es eine sauberere Lösung. Sprechen Sie über ein Überlaufmenü in der Symbolleiste oder in der Navigationsleiste?
Deividas Strioga
In der Navigationsleiste habe ich bereits eine andere Frage gestellt, außer dass das Hinzufügen eines Menüelements innerhalb einer Gruppe nicht funktioniert. Fügen
Sie
1

In meinem Fall hatte ich das Layout aufgeblasen, aber die untergeordneten Ansichten gaben null zurück. Ursprünglich hatte ich das:

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

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) findViewById(R.id.pbListviewFooter);
    tvText = (TextView) findViewById(R.id.tvListviewFooter);
    ...
}

Als ich es jedoch wie folgt änderte, funktionierte es:

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

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) footerView.findViewById(R.id.pbListviewFooter);
    tvText = (TextView) footerView.findViewById(R.id.tvListviewFooter);
    ...
}

Der Schlüssel bestand darin, speziell auf das bereits aufgeblasene Layout zu verweisen, um die untergeordneten Ansichten zu erhalten. Das heißt, um hinzuzufügen footerView:

  • footerView .findViewById ...
Suragch
quelle
0

Nach meiner Erfahrung kann dies auch passieren, wenn Ihr Code nach OnDestroyView aufgerufen wird (wenn sich das Fragment auf dem Backstack befindet). Wenn Sie die Benutzeroberfläche bei Eingabe von einem BroadCastReceiver aktualisieren, sollten Sie prüfen, ob dies der Fall ist .

Bisschen
quelle
0

LUFEN SIE DAS LAYOUT AUF !! (welches die ID enthält)

In meinem Fall hat findViewById () null zurückgegeben, da das Layout, in das das Element geschrieben wurde, nicht aufgeblasen wurde ...

Z.B. fragment_layout.xml

<ListView
android:id="@+id/listview">

findViewById (R.id.listview) gab null zurück, da ich inflater.inflate nicht ausgeführt hatte (R.layout.fragment_layout, ..., ...); bevor.

Hoffe, diese Antwort hilft einigen von euch.

ARCHE
quelle
0

Mein Fix war, nur das Projekt zu bereinigen.

Liangjun
quelle
0

findViewById kann auch null zurückgeben, wenn Sie sich in einem Fragment befinden. Wie hier beschrieben: findViewById in Fragment

Sie sollten getView () aufrufen, um die Ansicht der obersten Ebene innerhalb eines Fragments zurückzugeben. Dann finden Sie die Layoutelemente (Schaltflächen, Textansichten usw.)

Technokrat
quelle
0

Ich habe versucht, all das zu tun, nichts hat funktioniert. Also musste ich mein ImageView statisch machenpublic static ImageView texture; und dann texture = (ImageView) findViewById(R.id.texture_back);denke ich nicht, dass es ein guter Ansatz ist, aber das hat wirklich für meinen Fall funktioniert :)

Tabish
quelle
Entschuldigung, ich denke, statische Ansicht ist eine schlechte Idee
vuhung3990
0

In meinem Fall hat findViewById null zurückgegeben, als ich den Aufruf von einem übergeordneten Objekt in ein vom übergeordneten Objekt instanziiertes Adapterobjekt verschoben habe. Nachdem ich die hier aufgeführten Tricks erfolglos ausprobiert hatte, verschob ich die findViewById zurück in das übergeordnete Objekt und übergab das Ergebnis als Parameter während der Instanziierung des Adapterobjekts. Zum Beispiel habe ich dies im übergeordneten Objekt getan:

 Spinner hdSpinner = (Spinner)view.findViewById(R.id.accountsSpinner);

Dann habe ich den hdSpinner als Parameter beim Erstellen des Adapterobjekts übergeben:

  mTransactionAdapter = new TransactionAdapter(getActivity(),
        R.layout.transactions_list_item, null, from, to, 0, hdSpinner);
Lexo
quelle
0

Es stürzte für mich ab, weil eines der Felder in meiner Aktivitäts-ID mit der ID in einer anderen Aktivität übereinstimmte. Ich habe es behoben, indem ich eine eindeutige ID angegeben habe.

In meiner loginActivity.xml-Passwortfeld-ID war "Passwort". In meiner Registrierungsaktivität habe ich es einfach behoben, indem ich die ID r_password angegeben habe, dann hat es kein Null-Objekt zurückgegeben:

password = (EditText)findViewById(R.id.r_password);
Jageloo Yadav
quelle
0

Ich hatte ein ähnliches Problem, als ich versuchte, eine benutzerdefinierte Ansicht für a zu erstellen ListView.

Ich habe es einfach dadurch gelöst:

public View getView(int i, View view, ViewGroup viewGroup) {

    // Gets the inflater
    LayoutInflater inflater = LayoutInflater.from(this.contexto);

    // Inflates the layout
    ConstraintLayout cl2 = (ConstraintLayout) 
    inflater.inflate(R.layout.custom_list_view, viewGroup, false);

    //Insted of calling just findViewById, I call de cl2.findViewById method. cl2 is the layout I have just inflated. 
     TextView tv1 = (TextView)cl2.findViewById(cl2);
Rafael Costa
quelle
0

Möglichkeiten zum Debuggen und Finden des Problems:

  • Kommentieren Sie alle findViewById in Ihrer Aktivität aus.
  • Kommentieren Sie alles außer onCreate und setContentView aus
  • Führen Sie das Projekt aus und prüfen Sie, ob ein Layout festgelegt ist

In meinem Fall habe ich activity_main.xml sowohl in meinem App-Modul als auch in meinem Bibliotheksmodul verwendet. Als ich die obigen Schritte ausführte, wurde anstelle des Layouts, das ich in der Bibliothek entworfen hatte, das Layout im App-Modul aufgeblasen.

Also habe ich den Dateinamen activity_main.xml in activity_main_lib.xml geändert.

Stellen Sie daher sicher, dass Sie in Ihrem gesamten Projekt keine doppelten Layoutnamen haben .

Reejesh PK
quelle