web-dev-qa-db-fra.com

findViewByID renvoie la valeur null

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

La plupart d'entre eux ont pour conseil d'utiliser Android:id au lieu de id dans le fichier XML. J'ai fait.

J'ai appris auprès d'autres personnes que View.findViewById fonctionnait différemment de Activity.findViewById. Je me suis occupé de ça aussi.

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 retourne null. En faisant cela, mon activité fonctionne bien. Alors c'est peut-être à cause des différences Activity.findViewById et View.findViewById. J'ai donc stocké localement le contexte transmis au constructeur de la vue douane et essayé:

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

qui a également retourné null.

Ensuite, j'ai changé mon affichage personnalisé pour étendre ViewGroup à la place View et j'ai modifié le location_layout.xml afin de permettre à TextView d'être un enfant direct de mon affichage personnalisé, de sorte que le View.findViewById fonctionne normalement. Surprise: ça n'a rien résolu.

Alors qu'est-ce que je fais mal? 

Je vais apprécier tous les commentaires.

224
Thomas

qui retourne null

Peut-être parce que vous l'appelez trop tôt. Attendez que onFinishInflate(). Voici un exemple de projet démontrant qu'une View personnalisée accède à son contenu.

245
CommonsWare

Peut-être appelez-vous findViewById avant d'appeler setContentView? Si c'est le cas, essayez d'appeler findViewByIdAPR&EGRAVE;Sen appelant setContentView

130
Bayram Boyraz

Assurez-vous de ne pas avoir 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 présentation existante, mais j'ai oublié de mettre à jour la version hdpi. Si vous oubliez de mettre à jour toutes les versions du fichier de disposition, cela fonctionnera pour certaines densités d'écran mais pas pour d'autres.

89
Joe

Dans mon cas, j'avais 2 activités dans mon projet, main.xml et main2.xml. Depuis le début, main2 était une copie de main, et tout a bien fonctionné, jusqu'à ce que j'ajoute new TextView à main2. Le R.id.textview1 est donc disponible 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, dans le constructeur onCreate, j'instanciais non pas main2, mais l'autre. J'ai eu:

setContentView(R.layout.main);

au lieu de 

setContentView(R.layout.main2);

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

15
infografnet

Aux côtés des causes classiques, mentionnées ailleurs:

  • Assurez-vous d'avoir appelé setContentView() avant findViewById()
  • Assurez-vous que la id souhaitée se trouve dans la vue ou la présentation que vous avez donnée à setContentView()
  • Assurez-vous que la variable id n'est pas dupliquée par inadvertance dans différentes dispositions

Il y en a un que j'ai trouvé pour les vues personnalisées dans les dispositions 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, l’attribut id fonctionnait parfois pour toutes les vues de la présentation, à l’exception de celles personnalisées. La solution que j'utilise est:

  1. Remplacez chaque vue personnalisée par une FrameLayout avec les mêmes propriétés de présentation que vous souhaiteriez pour la vue personnalisée. Donnez-lui une id appropriée, disons 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);
    

    qui met la vue personnalisée dans le cadre.

13
Neil Townsend

FindViewById peut être null si vous appelez le super constructeur incorrect dans une vue personnalisée. La balise ID fait partie de attrs. Par conséquent, 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);
}
12
repkap11
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }
8
Jonathan

Une réponse pour ceux qui utilisent ExpandableListView et rencontrent 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é ceci ici .

6
Josh Metcalfe

Je suis assez nouveau sur Android/Eclipse. Par erreur, j'ai ajouté les éléments d'interface utilisateur à activity_main.xml au lieu de fragment_main.xml. Il m'a fallu quelques heures pour comprendre cela ...

5
lama12345

FWIW, je ne vois pas que quiconque ait résolu ce problème de la même manière que j'en avais besoin. Aucune plainte au moment de la compilation, mais je obtenais une vue nulle au moment de l'exécution et appelais les choses dans le bon ordre. C'est, findViewById () après setContentView () . Le problème s'est avéré que mon point de vue est défini dans content_main.xml, mais dans mon activité_main.xml, il manquait cette seule déclaration: 

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

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

4
ferris

Mon cas n’est plus comme ci-dessus, aucune solution n’a fonctionné. Je suppose que mon point de vue était trop profond dans la hiérarchie. Je l'ai déplacé d'un niveau et ce n'était plus nul.

3
Deividas Strioga

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

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

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

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

Je voulais juste jeter mon cas spécifique ici. Peut aider quelqu'un en bout de ligne.

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

Vue parente:

<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) renverrait toujours la valeur 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
John D.

Dans mon cas, j'utilisais ExpandableListView et j'avais défini Android:transcriptMode="normal". Cela entraînait la disparition de quelques enfants du groupe extensible et j'avais l'habitude d'obtenir l'exception NULL chaque fois que j'utilisais la liste déroulante.

2
Jeevan

Pour moi, j'avais deux mises en page 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 la même chose avec l'autre xml ou vous ne recevrez pas d'erreur avant de l'exécuter/le déboguer et il ne trouvera pas l'identifiant que vous n'avez pas changé. Oh bêtises, pourquoi dois-tu me punir ainsi?

2
ColossalChris

J'ai le même problème, mais je pense que cela vaut la peine de partager avec vous les gars . Si vous devez trouver ViewById dans une présentation 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 que la vue est gonflée . C'est une méthode que vous pouvez remplacer par onFinishInflate.

2
Shaw

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

J'ai finalement compris ce qui se passait. Eclipse utilisait toujours le fichier XML de mise en forme de la bibliothèque pour chaque cellule du GridView, même si cela n’indiquait rien. Dans mon adaptateur personnalisé, il était indiqué qu'il utilisait la ressource xml de mon propre projet, même si ce n'était pas le cas au moment de l'exécution.

Je me suis donc assuré que mes modèles et identifiants XML personnalisés étaient différents de ceux qui se trouvaient toujours dans la bibliothèque, nettoyaient le projet, puis lisaient les modèles personnalisés appropriés présents dans mon projet.

En bref, faites attention si vous écrasez l'adaptateur d'une bibliothèque tierce et spécifiez votre propre layout XML pour l'adaptateur à utiliser. Si votre mise en page dans votre projet porte le même nom de fichier que celui de la bibliothèque, vous rencontrerez peut-être un bogue très difficile à trouver!

2
JDJ

En plus des solutions ci-dessus, vous vous assurez que le
tools:context=".TakeMultipleImages"dans la mise en page est la même valeur dans le fichier mainfest.xml:
Android:name=".TakeMultipleImages" pour le même élément d'activité . il se produit lorsque vous utilisez copier et coller pour créer une nouvelle activité

2
user2982286

J'ai essayé tout ce qui précède, rien ne fonctionnait .. J'ai donc dû créer mon ImageView statique public static ImageView texture;, puis 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 :) 

1
Tabish

Dans mon cas, la disposition avait été gonflée, mais les vues enfant renvoyaient la valeur null. A 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é pour ceci, 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);
    ...
}

L'important était de faire spécifiquement référence à la présentation déjà gonflée afin d'obtenir les vues enfants. C'est-à-dire d'ajouter footerView:

  • footerView . findViewById ...
1
Suragch

Dans mon cas, findViewById a renvoyé la valeur 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 listées ici sans succès, j'ai replacé 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);

Ensuite, j'ai passé hdSpinner en tant que 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
Lexo

Ma solution était de simplement nettoyer le projet. 

0
Liangjun

findViewById peut également renvoyer null si vous êtes à l'intérieur d'un fragment. Comme décrit ici: findViewById in Fragment

Vous devriez appeler getView () pour retourner la vue de niveau supérieur dans un fragment. Ensuite, vous pouvez trouver les éléments de mise en page (boutons, textviews, etc.)

0
technocrat

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 est sur la pile d'arrière-plan.) Si vous mettez à jour l'interface utilisateur à partir de l'entrée d'un BroadCastReceiver, vous devez vérifier si c'est le cas .

0
Tad

INFLATEZ LA DISPOSITION !! (qui contient l'id)

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

Par exemple . Fragment_layout.xml

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

findViewById (R.id.listview) a renvoyé la valeur null, car je ne l'avais pas encore fait. avant cela.

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

0
Akshayraj Kore

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

Dans mon loginActivity.xml, l'identifiant du champ de mot de passe était "password". Dans mon activité d'enregistrement, je l'ai simplement corrigé en donnant à id r_password, puis il a renvoyé l'objet non null:

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

Je rencontrais un problème similaire lorsque je tentais de créer une vue personnalisée pour un ListViewname__.

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
Rafael Costa