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.
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.
Peut-être appelez-vous findViewById
avant d'appeler setContentView
? Si c'est le cas, essayez d'appeler findViewById
APR&EGRAVE;Sen appelant setContentView
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.
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.
Aux côtés des causes classiques, mentionnées ailleurs:
setContentView()
avant findViewById()
id
souhaitée se trouve dans la vue ou la présentation que vous avez donnée à setContentView()
id
n'est pas dupliquée par inadvertance dans différentes dispositionsIl 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:
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
.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.
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);
}
@Override
protected void onStart() {
// use findViewById() here instead of in onCreate()
}
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 .
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 ...
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.
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.
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);
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">
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.
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?
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
.
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!
En plus des solutions ci-dessus, vous vous assurez que letools: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é
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 :)
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
:
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);
Ma solution était de simplement nettoyer le projet.
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.)
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 .
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.
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);
Je rencontrais un problème similaire lorsque je tentais de créer une vue personnalisée pour un ListView
name__.
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);