How can I assign an ID to a view programmatically?
AndroidAndroid ViewAndroid ResourcesFindviewbyidAndroid IdentifiersAndroid Problem Overview
In an XML file, we can assign an ID to a view like android:id="@+id/something"
and then call findViewById()
, but when creating a view programmatically, how do I assign an ID?
I think setId()
is not the same as default assignment. setId()
is extra.
Can anybody correct me?
Android Solutions
Solution 1 - Android
id
overview
Android An Android id
is an integer commonly used to identify views; this id
can be assigned via XML (when possible) and via code (programmatically.) The id
is most useful for getting references for XML-defined View
s generated by an Inflater
(such as by using setContentView
.)
id
via XML
Assign - Add an attribute of
android:id="@+id/
somename"
to your view. - When your application is built, the
android:id
will be assigned a uniqueint
for use in code. - Reference your
android:id
'sint
value in code using "R.id.
somename" (effectively a constant.) - this
int
can change from build to build so never copy an id fromgen/
package.name/R.java
, just use "R.id.
somename". - (Also, an
id
assigned to aPreference
in XML is not used when thePreference
generates itsView
.)
id
via code (programmatically)
Assign - Manually set
id
s usingsomeView.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.
id
s
Uniqueness of XML
-assignedid
s will be unique.- Code-assigned
id
s do not have to be unique - Code-assigned
id
s can (theoretically) conflict withXML
-assignedid
s. - These conflicting
id
s won't matter if queried correctly (keep reading).
id
s don't matter
When (and why) conflicting findViewById(int)
will iterate depth-first recursively through the view hierarchy from the View you specify and return the firstView
it finds with a matchingid
.- As long as there are no code-assigned
id
s assigned before an XML-definedid
in the hierarchy,findViewById(R.id.somename)
will always return the XML-defined View soid
'd.
ID
s
Dynamically Creating Views and Assigning -
In layout XML, define an empty
ViewGroup
withid
. -
Such as a
LinearLayout
withandroid:id="@+id/placeholder"
. -
Use code to populate the placeholder
ViewGroup
withView
s. -
If you need or want, assign any
id
s that are convenient to each view. -
Query these child views using placeholder.findViewById(convenientInt);
-
API 17 introduced
View.generateViewId()
which allows you to generate a unique ID.
If you choose to keep references to your views around, be sure to instantiate them with getApplicationContext()
and be sure to set each reference to null in onDestroy
. Apparently leaking the Activity
(hanging onto it after is is destroyed) is wasteful.. :)
android:id
for use in code
Reserve an XML API 17 introduced View.generateViewId()
which generates a unique ID. (Thanks to take-chances-make-changes for pointing this out.)*
If your ViewGroup
cannot be defined via XML (or you don't want it to be) you can reserve the id via XML to ensure it remains unique:
Here, values/ids.xml defines a custom id
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="reservedNamedId" type="id"/>
</resources>
Then once the ViewGroup or View has been created, you can attach the custom id
myViewGroup.setId(R.id.reservedNamedId);
id
example
Conflicting For clarity by way of obfuscating example, lets examine what happens when there is an id
conflict behind the scenes.
layout/mylayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/placeholder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
To simulate a conflict, lets say our latest build assigned R.id.placeholder
(@+id/placeholder
) an int
value of 12
..
Next, MyActivity.java defines some adds views programmatically (via code):
int placeholderId = R.id.placeholder; // placeholderId==12
// returns *placeholder* which has id==12:
ViewGroup placeholder = (ViewGroup)this.findViewById(placeholderId);
for (int i=0; i<20; i++){
TextView tv = new TextView(this.getApplicationContext());
// One new TextView will also be assigned an id==12:
tv.setId(i);
placeholder.addView(tv);
}
So placeholder
and one of our new TextView
s both have an id
of 12! But this isn't really a problem if we query placeholder's child views:
// Will return a generated TextView:
placeholder.findViewById(12);
// Whereas this will return the ViewGroup *placeholder*;
// as long as its R.id remains 12:
Activity.this.findViewById(12);
*Not so bad
Solution 2 - Android
You can just use the View.setId(integer)
for this. In the XML, even though you're setting a String id, this gets converted into an integer. Due to this, you can use any (positive) Integer for the Views
you add programmatically.
> According to View
documentation
>
> > The identifier does not have to be unique in this view's hierarchy.
> > The identifier should be a positive number.
>
> So you can use any positive integer you like, but in this case there
> can be some views with equivalent id's. If you want to search for some
> view in hierarchy calling to setTag with some key objects may be
> handy.
Credits to this answer.
Solution 3 - Android
Yes, you can call setId(value)
in any view with any (positive) integer value that you like and then find it in the parent container using findViewById(value)
. Note that it is valid to call setId()
with the same value for different sibling views, but findViewById()
will return only the first one.