androidandroid-viewandroid-resourcesfindviewbyidandroid-identifiers

How can I assign an ID to a view programmatically?


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?


Solution

  • Android id overview

    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 Views generated by an Inflater (such as by using setContentView.)

    Assign id via XML

    Assign id via code (programmatically)

    Uniqueness of ids

    When (and why) conflicting ids don't matter

    Dynamically Creating Views and Assigning IDs

    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.. :)

    Reserve an XML android:id for use in code

    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);
    

    Conflicting id example

    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 TextViews 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