7

In my app I am creating Views - in this case an EditText - dynamically. But every View I add needs to have a unique id.

EditText editText = new EditText(context);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
editText.setLayoutParams(params);

// Which value am I supposed to use here?
editText.setId(value);

layout.addView(editText);

I am afraid of conflicts if I assign a random value and I cannot think of any way to generate ids without the possibility of conflicts.

Please not that I know that one can define a fixed set of ids in res/values/ids.xml, but that is not what I want! I need to create the ids dynamically! I have no idea how many I need.

So is there any safe way to generate ids?

Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
Yatin
  • 183
  • 1
  • 12
  • 1
    +1,see this http://stackoverflow.com/questions/8937380/how-to-set-id-of-dynamic-created-layout similar to your issue. – nobalG Jul 18 '14 at 10:37
  • @nobalG i wanted a method besides the one which uses id.xml file – Yatin Jul 18 '14 at 12:21

2 Answers2

8

There are multiple ways you can reliably generate ids for your Views. Some can be used to dynamically generate ids at runtime, others can be used to statically define a fixed number of ids. I will go over a few solutions in this answer.


Statically creating a fixed number of ids

Create a new xml file in res/values called ids.xml and add elements with the type id:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <item name="name" type="id" />     <!-- Creates the id R.id.name -->
    <item name="example" type="id" />  <!-- Creates the id R.id.example -->

</resources>

You can generate ids for other resources as well! Just change the type.


Dynamically generating ids from API level 17+

With API level 17 a new method was added to the View class:

int id = View.generateViewId();

With it you can create as many ids as you need dynamically!


Dynamically generating ids before API level 17

As @Apoorv suggested you can view the source code of generateViewId() here. By copying the code we can use this method even before API level 17:

private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

public static int generateViewId() {
    for (; ; ) {
        final int result = sNextGeneratedId.get();

        // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
        int newValue = result + 1;
        if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.

        if (sNextGeneratedId.compareAndSet(result, newValue)) {
            return result;
        }
    }
}

Just include it in a helper class and you are all set!

Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
  • thanks....but i want to know besides this, where i don't have to create pre-defined id because i don't know how many will be created.. – Yatin Jul 18 '14 at 10:46
  • I have added a solution to create the ids dynamically at runtime. – Xaver Kapeller Jul 18 '14 at 11:05
  • @XaverKapeller [generateViewID()](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.1_r1.2/android/view/View.java#View.generateViewId%28%29) shows how the method generates unique ids. Can it be used directly before API 17 seeing as how it doesn't require anything special? Just an `AtomicInteger` – Apoorv Jul 18 '14 at 11:23
  • @Apoorv Very nice, I already updated my answer. This solution is better than everything else I have seen, but I have to admit it's kinda funny that all this method does is glorified incrementing. It's just a better version of the for loop suggested everywhere else. – Xaver Kapeller Jul 18 '14 at 12:40
  • @XaverKapeller Yes i was wondering the same thing. I mean it does not cross reference anywhere that whether the updated number is an already existing id or not – Apoorv Jul 18 '14 at 12:43
  • @Apoorv I think it does not matter if there are duplicates. It's not really a good example, but think of a `ListView`, in every row the ids are the same, but it still works because you are only looking for `Views` in one row at a time. The same thing applies everywhere else. When you are generating ids this way you just have to know what you are doing. – Xaver Kapeller Jul 18 '14 at 12:51
  • @XaverKapeller Oh yes I think I got the idea. Something like it does not matter if other `Views` have the same id as long as there exists a `View` with the id you are looking for in the `ViewGroup` you are looking for it in. – Apoorv Jul 18 '14 at 12:57
  • @Apoorv Exactly. I tested it right now and it seems that if there are multiple `Views` with the same id, it picks the first one it encounters in other words it traverses the view hierarchy from top. So if you have a layout with a `TextView` and a `ListView` and you are looking for the `TextView` but there are other `TextViews` with the same id in the `ListView` then it would pick the first `TextView` outside of the `ListView` because it is higher up in the view hierarchy. It seems this whole thing is pretty safe when it comes to the ids. – Xaver Kapeller Jul 18 '14 at 13:02
  • @Apoorv This is how `findViewById()` is implemented in a `ViewGroup`: [**Link to source**](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/view/ViewGroup.java#ViewGroup.findViewTraversal%28int%29). `findViewTraversal()` is called by `findViewById()` if the id does not match the id of the `ViewGroup`. – Xaver Kapeller Jul 18 '14 at 13:07
  • @XaverKapeller I was just trying to the same thing. – Apoorv Jul 18 '14 at 13:12
8

Assign id via code (programmatically)

  • Manually set ids using someView.setId(int);
  • The int must be positive, but is otherwise arbitrary- it can be whatever you want (keep reading if this is frightful.)
  • For example, if creating and numbering several views representing items, you could use their item number.

Normally we do:

To assign id -

for(int i =0 ; i < yourIDcount ; i++){
    yourView.setId(i);
}

To get id -

View.findViewById(yourView.getId());

Also,

API 17 introduced View.generateViewId() which generates a unique ID.

Check:

how-can-i-assign-an-id-to-a-view-programmatically and android-assign-and-retrieve-ids-dynamically.

Community
  • 1
  • 1
sjain
  • 23,126
  • 28
  • 107
  • 185
  • 2
    How does this make sense: `View.findViewById(yourView.getId());`? You would need to already have an instance of the `View` to call `findViewById()` in the first place. – Xaver Kapeller Jul 18 '14 at 10:44
  • @XaverKapeller - This isn't necessary. The `android.view.View` is in the android package and you can directly call `findViewById()` on it to get the view by its id. You can check - http://developer.android.com/reference/android/view/View.html – sjain Jul 18 '14 at 10:51
  • @VedPrakash `findViewById` is not a `static` method. You can't call `View.findViewById`. You need an object to call it. – Apoorv Jul 18 '14 at 10:54
  • I am talking about the `yourView.getId()`. You call `getId()` on the `View` instance you are trying to get so obviously you already have the instance and don't need to find it again. – Xaver Kapeller Jul 18 '14 at 10:59
  • @Apoorv - `findViewById` is the public final method that looks for a child view with the given id. If this view has the given id, it returns this view. Search for `View.findViewById()` in the developer.android.com/reference/android/view/View.html – sjain Jul 18 '14 at 11:00
  • Yes exactly!! It is a `public final` method and not `public static final`. You need an object of `View` so if you try to call `View.findViewById` it won't even compile. – Apoorv Jul 18 '14 at 11:02
  • @XaverKapeller - When you are creating the view dynamically, you created its instance and then called `yourView.setId()` to set the id and `yourView.getId()` to get the id back. :) – sjain Jul 18 '14 at 11:03
  • I realise that, I am just saying, calling `findViewById()` is kinda useless if you already have the instance :) – Xaver Kapeller Jul 18 '14 at 11:06
  • @Apoorv - Correct. So my understanding is you have to have `View view` then `view.findViewById(someID)`. This is what is mentioned in the docs also. – sjain Jul 18 '14 at 11:06
  • Yes you have to use `view.findViewById(someID)` and not `View.findViewById(someID)` – Apoorv Jul 18 '14 at 11:07
  • @Apoorv - I have to say that this is general way of explaining :) – sjain Jul 18 '14 at 11:10
  • You can use `View.generateViewId()` for unique id – Raghu Krishnan R Nov 26 '20 at 18:36