Question

From Android developer documentation, a statement reads as under:

An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree you are searching (which may often be the entire tree, so it's best to be completely unique when possible).

Please help me understand, with an example, what is meant by 'part of the tree you are searching'?

Example, given following:

<AnOutterLayout>

  <Button android:id="@+id/my_button".../>

  <ASuitableInnerLayout>

    <Button android:id="@+id/my_button".../>

  </ASuitableInnerLayout>

</AnOutterLayout>

If I have:

Button myButton = (Button) findViewById(R.id.my_button);

What will be search tree here?

Thanks!

Was it helpful?

Solution

The "part of the tree you are searching" is typically the children of the ViewGroup you're calling findViewById on.

In an Activity, the findViewById method is implemented like this (source):

public View findViewById(int id) {
    return getWindow().findViewById(id);
}

Ok, so how does a Window implement findViewById (source)?

public View findViewById(int id) {
    return getDecorView().findViewById(id);
}

getDecorView returns a View - and all that the implementation of View does is return itself (if the views ID matches the one passed in), or null (source):

public final View findViewById(int id) {
    if (id < 0) {
        return null;
    }
    return findViewTraversal(id);
}

protected View findViewTraversal(int id) {
    if (id == mID) {
        return this;
    }
    return null;
}

It's much more interesting if we look at the implementation for a ViewGroup (source):

protected View findViewTraversal(int id) {
    if (id == mID) {
        return this;
    }

    final View[] where = mChildren;
    final int len = mChildrenCount;

    for (int i = 0; i < len; i++) {
        View v = where[i];

        if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
            v = v.findViewById(id);

            if (v != null) {
                return v;
            }
        }
    }

    return null;
}

So you see a ViewGroup traverses its children searching for the ID you pass in. I'm not certain of the order of mChildren, but I suspect it'll be in the order you add the views to the hierarchy (just checked - addView(View child) does add views to the end of the mChildren list, where as addView(View child, int index) adds the view at index position in the list).

So, for your example, which button was returned would depend on which ViewGroup you were calling findViewById on.

If you called anOutterLayout.findViewById(R.id.my_button), you'd get the first button - as this is the first child element it comes across that contains that id.

If you called anInnerLayout.findViewById(R.id.my_button), you'd get the second button.

However, if your layout file looked like this:

<AnOutterLayout>

  <ASuitableInnerLayout>

    <Button android:id="@+id/my_button".../>

  </ASuitableInnerLayout>

  <Button android:id="@+id/my_button".../>

</AnOutterLayout>

Then anOutterLayout.findViewById(R.id.my_button) would actually return the button inside the inner layout - as this view was added to the hierarchy earlier, and is therefore earlier in the list of children for that view.

This assumes that views are added in the order they're present in the XML view hierarchy.

OTHER TIPS

The button in the outter layer will be called first.

This post has a well-explained answer for your question

Are Android View id supposed to be unique?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top