findViewByID renvoie null


252

Tout d'abord: oui, j'ai lu toutes les autres discussions sur ce sujet. Et pas seulement ceux de ce site ... (vous voyez, je suis un peu frustré)

La plupart d'entre eux sont accompagnés des conseils à utiliser android:idplutôt que simplement iddans le fichier XML. J'ai fait.

D'après d'autres, j'ai appris que cela View.findViewByIdfonctionne différemment Activity.findViewById. J'ai aussi géré ça.

Dans mon location_layout.xml, j'utilise:

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

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

Dans mon activité, je fais:

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

et dans ma classe de vue personnalisée:

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

qui revient null. Ce faisant, mon activité fonctionne bien. C'est peut-être à cause des différences Activity.findViewByIdet View.findViewById. J'ai donc stocké localement le contexte transmis au constructeur de la vue des douanes et j'ai essayé:

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

qui est également revenu null.

Ensuite, j'ai changé ma vue personnalisée pour l'étendre à la ViewGroupplace Viewet j'ai changé location_layout.xmlpour laisser le TextViewêtre un enfant direct de ma vue personnalisée, afin que le View.findViewByIdfonctionne comme prévu. Surprise: cela n'a rien résolu.

Alors qu'est-ce que je fais mal?

J'apprécierai tout commentaire.


6
Cela peut se produire si le projet est également corrompu. Je l'ai corrigé en nettoyant le projet
Pacerier

1
passé vue contextuelle incorrecte merci
izzy

1
@Pacerier merci. qui a résolu mon problème. Je commence à détester la programmation Android dans Xamarin)
Artiom

@Pacerier "Clean project" a également résolu mon problème. Il semble que Dropbox ait corrompu le projet.
Kohki Mametani

Réponses:


271

qui renvoie null

Peut-être parce que vous l'appelez trop tôt. Attendez onFinishInflate(). Voici un exemple de projet démontrant une personnalisation de l' Viewaccès à son contenu.


67
OMG! Je ne peux pas croire que je passe des jours sur quelque chose de si trivial. J'ai déplacé setContentView () au-dessus de l'appel findViewById () et cela n'a pas fonctionné. Merci!
agentcurry

2
@CommonsVoyez-vous que le bon projet? Je ne vois onFinishInflate nulle part dans github.com/commonsguy/cw-advandroid/tree/master/Animation/…
likejudo

1
@likejiujitsu: Il pourrait avoir eu cela en 2010. J'ai mis à jour le lien vers un nouveau projet qui a onFinishInflate().
CommonsWare

3
J'ai appelé mon setContentView avant findViewById et il est toujours nul. Je fais référence à un EditText
Neon Warge

1
Toujours créer un lien vers des validations GitHub fixes (par exemple github.com/commonsguy/cw-omnibus/tree/… ) et ne jamais supprimer de repos ou de rebase ;-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

145

Peut-être appelez-vous findViewByIdavant d'appeler setContentView? Si tel est le cas, essayez d'appeler findViewById APRÈS avoir appelésetContentView


1
Une erreur si facile à faire, mais malheureusement, c'est ce que j'avais fait. Le débogueur n'est d'aucune utilité car il a dit que l'erreur était sur ma nouvelle ligne d'intention et non dans la nouvelle activité que j'appelais. Merci!
edude05

6
En fait, j'ai eu cette erreur parce que j'appelais setContentView pointant vers la mauvaise vue ... malheureusement, le compilateur ne détecte pas ce type d'erreur.
HeatfanJohn

Oui, j'ai supprimé setContentView par erreur et je n'ai pas compris pourquoi mon programme a commencé à s'écraser.
Ronen Festinger

100

Assurez-vous que vous n'avez pas plusieurs versions de votre mise en page pour différentes densités d'écran. J'ai rencontré ce problème une fois lors de l'ajout d'un nouvel identifiant à une mise en page existante, mais j'ai oublié de mettre à jour la version hdpi. Si vous oubliez de mettre à jour toutes les versions du fichier de mise en page, cela fonctionnera pour certaines densités d'écran mais pas pour d'autres.


8
MERCI! C'était ça. (Dans mon cas, j'ai plusieurs versions pour différentes versions d'Android). Je l'oublie tout le temps, même si je mets un commentaire gigantesque en haut et en bas de chaque fichier de mise en page. Je souhaite que le compilateur fasse une erreur ou un gros avertissement si cela se produit.
tiktak

Ding ding ding, merci beaucoup! Je penchais mon cerveau sur ce lol
Zach

21

FindViewById peut être null si vous appelez le mauvais super constructeur dans une vue personnalisée. La balise ID fait partie des attrs, donc si vous ignorez les attrs, vous supprimez l'ID.

Ce serait faux

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

C'est correct

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

1
Merci beaucoup monsieur! Si insouciant que je suis, je doutais même qu'il y avait quelque chose de mal avec mon IDE. Quelle chance de rencontrer votre réponse.
EffectiveMatrix

J'ai fait cette erreur en créant ma vue personnalisée. Merci, repkap11.
Andrew F.

15

Dans mon cas, j'avais 2 activités dans mon projet, main.xmlet main2.xml. Dès le début, main2était une copie main, et tout a bien fonctionné, jusqu'à ce que j'ajouté nouveau TextViewà main2, de sorte que le sont R.id.textview1devenus disponibles pour le reste de l' application. Ensuite, j'ai essayé de le récupérer par un appel standard:

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

et c'était toujours nul. Il s'est avéré que chez le onCreateconstructeur, je n'instanciais pas main2, mais l'autre. J'ai eu:

setContentView(R.layout.main);

au lieu de

setContentView(R.layout.main2);

Je l'ai remarqué après mon arrivée ici, sur le site.


14

A côté des causes classiques, évoquées ailleurs:

  • Assurez-vous que vous avez appelé setContentView()avantfindViewById()
  • Assurez-vous que l'image que idvous voulez se trouve dans la vue ou la mise en page que vous avez donnée àsetContentView()
  • Assurez-vous que le idn'est pas accidentellement dupliqué dans différentes dispositions

Il y en a un que j'ai trouvé pour les vues personnalisées dans les mises en page standard, ce qui va à l'encontre de la documentation:

En théorie, vous pouvez créer une vue personnalisée et l'ajouter à une mise en page ( voir ici ). Cependant, j'ai constaté que dans de telles situations, parfois l' idattribut fonctionne pour toutes les vues de la mise en page, à l'exception des vues personnalisées. La solution que j'utilise est:

  1. Remplacez chaque vue personnalisée par un FrameLayoutavec les mêmes propriétés de mise en page que vous souhaitez que la vue personnalisée ait. Donnez-lui une réponse appropriée id, par exemple frame_for_custom_view.
  2. Dans onCreate:

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

    ce qui place la vue personnalisée dans le cadre.


Cela m'a aidé: "Assurez-vous que l'ID que vous voulez se trouve dans la vue ou la disposition que vous avez donnée à setContentView ()". Que faire quand c'est une sous-vue cependant? J'ai essayé d'obtenir la vue parent, puis faites parentView.findById () mais elle retourne toujours null
NaturalBornCamper

@naturalborncamper si vous postez une question séparée avec un exemple de code, je vais y jeter un œil.
Neil Townsend

Merci Neil, j'ai déjà posté et quelqu'un a indiqué une meilleure façon de le faire, bien que cela ne fonctionne pas exactement comme cela devrait être, j'ai donc dû utiliser une stratégie différente: stackoverflow.com/questions/47955376/…
NaturalBornCamper

9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }

6

Une réponse pour ceux qui utilisent ExpandableListView et se heurtent à cette question en fonction de son titre.

J'ai eu cette erreur en essayant de travailler avec TextViews dans mes vues enfant et groupe dans le cadre d'une implémentation ExpandableListView.

Vous pouvez utiliser quelque chose comme ce qui suit dans vos implémentations des méthodes getChildView () et getGroupView ().

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

J'ai trouvé ça ici .


5

Je suis assez nouveau sur Android / Eclipse, par erreur, j'ai ajouté des éléments d'interface utilisateur à la activity_main.xmlplace de fragment_main.xml. Cela m'a pris quelques heures pour comprendre cela ...


5

FWIW, je ne vois pas que quelqu'un ait résolu cela de la même manière que je le devais. Aucune plainte au moment de la compilation, mais j'obtenais une vue nulle au moment de l'exécution et j'appelais les choses dans le bon ordre. Autrement dit, findViewById () après setContentView (). Le problème s'est avéré que ma vue est définie dans content_main.xml, mais dans mon activity_main.xml, je manquais cette seule déclaration:

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

Lorsque j'ai ajouté cela à activity_main.xml, plus de NullPointer.


Le problème avec la copie collant un fragment est que vous oubliez parfois de changer certaines choses ... étant la disposition correcte pour gonfler l'une d'entre elles. Merci!
Pablo Quemé

3

J'ai eu le même problème. J'utilisais une bibliothèque tierce qui vous permet de remplacer leur adaptateur pour une GridView et de spécifier votre propre disposition pour chaque cellule GridView.

J'ai finalement réalisé ce qui se passait. Eclipse utilisait toujours le fichier XML de mise en page de la bibliothèque pour chaque cellule du GridView, même si cela ne donnait aucune indication à ce sujet. Dans mon adaptateur personnalisé, il a indiqué qu'il utilisait la ressource xml de mon propre projet même si au moment de l'exécution, ce n'était pas le cas.

Donc, ce que j'ai fait était de m'assurer que mes mises en page et identifiants xml personnalisés étaient différents de ceux qui se trouvaient toujours dans la bibliothèque, nettoyé le projet, puis il a commencé à lire les mises en page personnalisées correctes qui étaient dans mon projet.

En bref, soyez prudent si vous remplacez l'adaptateur d'une bibliothèque tierce et spécifiez votre propre format XML pour l'adaptateur à utiliser. Si votre mise en page à l'intérieur de votre projet a le même nom de fichier que celui de la bibliothèque, vous pourriez rencontrer un bogue vraiment difficile à trouver!


3

Dans mon cas particulier, j'essayais d'ajouter un pied de page à un ListView. L'appel suivant dans onCreate () retournait null.

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

Changer cela pour gonfler la vue de pied de page au lieu de la trouver par ID a résolu ce problème.

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

2

Dans mon cas, j'utilisais ExpandableListView et j'avais réglé android:transcriptMode="normal". Cela faisait disparaître quelques enfants du groupe extensible et j'obtenais une exception NULL chaque fois que j'utilisais la liste.


2

Pour moi, j'avais deux dispositions xml pour la même activité - une en mode portrait et une en paysage. Bien sûr, j'avais changé l'identifiant d'un objet dans le paysage xml mais j'avais oublié de faire le même changement dans la version portrait. Assurez-vous que si vous en changez un, vous faites de même avec l'autre xml ou vous n'obtiendrez pas d'erreur jusqu'à ce que vous l'exécutiez / déboguez et il ne trouvera pas l'id que vous n'avez pas changé. Oh stupides erreurs, pourquoi devez-vous me punir ainsi?


2

Définissez le contenu de l'activité à partir d'une ressource de mise en page. à savoir., setContentView(R.layout.basicXml);


2

En plus des solutions ci-dessus, vous vous assurez que la mise
tools:context=".TakeMultipleImages" en page a la même valeur dans le fichier mainfest.xml:
android:name=".TakeMultipleImages"pour le même élément d'activité. cela se produit lors de l'utilisation du copier-coller pour créer une nouvelle activité


2

J'ai le même problème, mais je pense que cela vaut la peine d'être partagé avec vous. Si vous devez trouver ViewById dans une mise en page personnalisée, par exemple:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

vous ne pouvez pas obtenir la vue dans le constructeur. Vous devez appeler findViewById une fois la vue gonflée. C'est une méthode que vous pouvez remplaceronFinishInflate


2

Je voulais juste jeter mon cas spécifique ici. Pourrait aider quelqu'un au bout du compte.

J'utilisais la directive dans mon XML UI Android comme ceci:

Vue parent:

<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" />

Vue enfant (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) retournerait toujours null. Mais, si j'ai déplacé l'ID de la vue enfant dans la balise include, cela a commencé à fonctionner.

Parent fixe:

<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" />

Enfant fixe:

<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">

2

Mon cas n'est pas comme ci-dessus, aucune solution n'a fonctionné. Je suppose que ma vue était trop profonde dans la hiérarchie de mise en page. Je l'ai déplacé d'un niveau et ce n'était plus nul.


J'ai le même problème, un niveau supérieur peut également être trouvé .. c'est assez ennuyeux et j'aimerais savoir pourquoi cela se produit car je ne peux pas faire mon menu comme je le veux
NaturalBornCamper

Les hiérarchies de mise en page profondes sont anti-modèle, il existe presque toujours une solution plus propre. Parlez-vous du menu de débordement dans la barre d'outils ou le tiroir de navigation?
Deividas Strioga

Tiroir de navigation, j'ai déjà posté une autre question, sauf que l'ajout d'un élément de menu dans un groupe ne fonctionne pas, l'ajoute simplement à la fin de tous les éléments: stackoverflow.com/questions/47955376/…
NaturalBornCamper

1

Dans mon cas, j'avais gonflé la mise en page, mais les vues enfant retournaient nulles. À l'origine, j'avais ceci:

@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);
    ...
}

Cependant, lorsque je l'ai changé comme suit, cela a fonctionné:

@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);
    ...
}

La clé était de référencer spécifiquement la disposition déjà gonflée afin d'obtenir les vues enfant. Autrement dit, pour ajouter footerView:

  • footerView .findViewById ...

0

D'après mon expérience, il semble que cela puisse également se produire lorsque votre code est appelé après OnDestroyView (lorsque le fragment se trouve sur la pile arrière.) Si vous mettez à jour l'interface utilisateur sur l'entrée d'un BroadCastReceiver, vous devez vérifier si c'est le cas .


0

GONFLEZ LA DISPOSITION !! (qui contient l'identifiant)

Dans mon cas, findViewById () a retourné null, car la disposition dans laquelle l'élément a été écrit n'était pas gonflée ...

Par exemple. fragment_layout.xml

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

findViewById (R.id.listview) a retourné null, car je n'avais pas fait inflater.inflate (R.layout.fragment_layout, ..., ...); avant cela.

J'espère que cette réponse aide certains d'entre vous.



0

findViewById peut également retourner null si vous êtes dans un fragment. Comme décrit ici: findViewById in Fragment

Vous devez appeler getView () pour renvoyer la vue de niveau supérieur à l'intérieur d'un fragment. Ensuite, vous pouvez trouver les éléments de mise en page (boutons, vues de texte, etc.)


0

J'ai essayé tout ce qui précède, rien ne fonctionnait .. j'ai donc dû rendre mon ImageView statique public static ImageView texture; et ensuite texture = (ImageView) findViewById(R.id.texture_back);, je ne pense pas que ce soit une bonne approche mais cela a vraiment fonctionné pour mon cas :)


désolé, je pense que la vue statique est une mauvaise idée
vuhung3990

0

Dans mon cas, findViewById a retourné null lorsque j'ai déplacé l'appel d'un objet parent vers un objet adaptateur instancié par le parent. Après avoir essayé les astuces répertoriées ici sans succès, j'ai replacé le findViewById dans l'objet parent et transmis le résultat en tant que paramètre lors de l'instanciation de l'objet adaptateur. Par exemple, je l'ai fait dans l'objet parent:

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

J'ai ensuite passé le hdSpinner comme paramètre lors de la création de l'objet adaptateur:

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

0

Il s'est bloqué pour moi car l'un des champs de mon ID d'activité correspondait à l'ID d'une autre activité. Je l'ai corrigé en donnant un identifiant unique.

Dans mon identifiant de champ de mot de passe loginActivity.xml, c'était "mot de passe". Dans mon activité d'enregistrement, je l'ai juste corrigé en donnant l'id r_password, puis il a renvoyé un objet non nul:

password = (EditText)findViewById(R.id.r_password);

0

J'étais confronté à un problème similaire lorsque j'essayais de créer une vue personnalisée pour a ListView.

Je l'ai résolu simplement en faisant ceci:

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);

0

Façons de déboguer et de trouver le problème:

  • Mettez en commentaire tous les findViewById de votre activité.
  • Commentez tout sauf onCreate et setContentView
  • Exécutez le projet et voyez si une disposition est définie

Dans mon cas, j'utilisais activity_main.xml à la fois dans mon module d'application et dans mon module de bibliothèque. Ainsi, lorsque j'ai effectué les étapes ci-dessus, au lieu de la mise en page que j'ai conçue dans la bibliothèque, la mise en page à l'intérieur du module d'application a été gonflée.

J'ai donc changé le nom du fichier activity_main.xml en activity_main_lib.xml.

Assurez-vous donc que vous n'avez pas de noms de mise en page en double dans l'ensemble de votre projet .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.