374 votes

Android: View.setID(int id) programmatically - comment éviter les conflits d'ID?

Je rajoute des TextView de façon programmative dans une boucle for et je les ajoute à une ArrayList.

Comment est-ce que j'utilise TextView.setId(int id)? Quel identifiant Integer est-ce que je choisis pour éviter les conflits avec d'autres identifiants?

649voto

xdevelopery Points 2710

À partir du niveau API 17 et supérieur, vous pouvez appeler: View.generateViewId()

Ensuite, utilisez View.setId(int).

Si votre application est ciblée à un niveau inférieur à 17, utilisez ViewCompat.generateViewId()

2 votes

J'ai mis cela dans mon code source car nous voulons prendre en charge des niveaux d'API inférieurs. Cela fonctionne mais la boucle infinie n'est pas une bonne pratique.

5 votes

@SimonXinCheng Les boucles infinies sont un pattern commun utilisé dans les algorithmes non bloquants. Par exemple, regardez l'implémentation des méthodes de AtomicInteger.

7 votes

Fonctionne très bien! Une remarque: d'après mes expériences, vous devez appeler setId() AVANT d'ajouter la vue à une disposition existante, sinon le OnClickListener ne fonctionnera pas correctement.

174voto

Aditya Points 106

Vous pouvez définir les identifiants que vous utiliserez plus tard dans la classe R.id en utilisant un fichier de ressources xml, et laisser Android SDK définir les valeurs uniques réelles lors de la compilation.

 res/values/ids.xml

Pour l'utiliser dans le code :

myEditTextView.setId(R.id.my_edit_text_1);

25 votes

Cela ne fonctionne pas lorsque j'ai un nombre inconnu d'éléments auxquels je vais attribuer des identifiants.

1 votes

@MooingDuck Je sais que c'est un an en retard, mais quand je dois attribuer des identifiants uniques au moment de l'exécution avec un nombre d'éléments inconnu, je utilise simplement "int currentId = 1000; whateverView.setId(currentId++); - Cela incrémente l'ID à chaque utilisation de currentId++, garantissant un ID unique, et je peux stocker les IDs dans mon ArrayList pour un accès ultérieur.

4 votes

@MikeinSAT: Cela garantit seulement qu'ils sont uniques entre eux. Cela ne signifie pas "qu'ils ne rentrent pas en conflit avec d'autres identifiants", ce qui est un élément clé de la question.

155voto

Nikolay Ivanov Points 5117

Selon la documentation de View

L'identifiant n'a pas besoin d'être unique dans la hiérarchie de cette vue. L'identifiant devrait être un nombre positif.

Vous pouvez donc utiliser n'importe quel entier positif que vous aimez, mais dans ce cas, il peut y avoir certaines vues avec des identifiants équivalents. Si vous voulez rechercher une vue dans la hiérarchie en appelant setTag avec certains objets clés pourrait être pratique.

2 votes

Intéressant, je n'étais pas au courant que les IDs n'ont pas besoin d'être uniques? Alors est-ce que findViewById fait des garanties quant à quelle vue est retournée s'il y en a plusieurs avec le même ID? Les docs ne mentionnent rien.

26 votes

Je pense que les documents mentionnent quelque chose à ce sujet. Si vous avez des vues avec le même ID dans la même hiérarchie, alors findViewById renverra le premier qu'il trouve.

0 votes

@kaneda je ne pense pas qu'il obtient le premier identifiant. Il obtient l'identifiant qui se trouve dans la mise en page que vous avez définie dans setContentView()

62voto

yenliangl Points 574

Aussi, vous pouvez définir ids.xml dans res/values. Vous pouvez voir un exemple exact dans le code source d'android.

samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemos/res/values/ids.xml

15 votes

Voici également une réponse avec cette approche : stackoverflow.com/questions/3216294/…

0 votes

Pour référence, j'ai trouvé le fichier dans: /samples/android-15/ApiDemos/src/com/example/android/apis/view/RadioGroup1.java

26voto

dilettante Points 189

Éditer : Comme mentionné par d'autres utilisateurs, cette approche est mauvaise pour les performances, il existe de nouvelles façons d'y parvenir.

Cela fonctionne pour moi :

static int id = 1;

// Renvoie un ID valide qui n'est pas utilisé
public int findId(){  
    View v = findViewById(id);  
    while (v != null){  
        v = findViewById(++id);  
    }  
    return id++;  
}

0 votes

Cela est un peu plus compliqué mais je parie que ça marchera. Utiliser des variables globales dans un environnement multithread finira sûrement par échouer un jour, surtout avec plusieurs cœurs.

3 votes

Aussi, n'est-ce pas potentiellement lent pour des mises en page compliquées ?

15 votes

findViewById() est une opération lente. L'approche fonctionne, mais au détriment des performances.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X