Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

findViewById(int) returns null for custom views, but not Android built-ins

The Situation: I have some custom components in my layout. I have a common layout frame that I load in my Activity base class's onCreate(), and then load my content layouts in my implementations using an inflater, setting the root to the content column of the main layout.

The Problem: When I grab a reference to the Views, to actually extract the user's input, Activity.findViewById() returns null. It is perhaps a clue that the CheckBox and Button I have in the layout do NOT return null; I get a valid reference to the widget.

Things I've Tried: I know I am properly loading and inflating the layout xml, because everything shows up, and the standard Views in the same layout can be found by ID. I can interact with my Views and put content into them and everything, but I can't get a reference to them in my code.

I have tried cleaning the project, multiple times. R.id is fresh and up-to-date.

I have checked the Console and Error Log, and there's no UI/XML errors reported.

I tried getting a handle to the root layout of the content I loaded for this activity, and calling View.findViewById() to get my references, and that returns null, too. If I examine the layout in the debugger, I can drill down and find my Views in mChildren.

Perhaps another clue:

public VideoChooser(Context pCtxt, AttributeSet pAttrs)
{
    super(pCtxt, pAttrs);
    Log.d("VideoChooser", "Expected ID: " + R.id.vchShareVids + " | actual: " + getId());
}

will result in the following output:

DEBUG/VideoChooser(10372): Expected ID: 2131296271 | actual: 268435456

The ID assigned to the View doesn't match the ID in R.id! Why would that be? I know it's loading the android:id attribute, or else it would be -1 (View.NO_ID).

The Common Layout Frame:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:foo="http://schemas.android.com/apk/res/com.foo"
    android:id="@+id/common_frame" android:orientation="vertical"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <!-- top banner -->
    <LinearLayout android:id="@+id/frame_header" android:orientation="horizontal"
        android:layout_height="wrap_content" android:layout_width="match_parent"
        android:layout_marginBottom="16dp">

        <ImageView android:src="@drawable/banner"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal" android:layout_weight="1" />

    </LinearLayout>

    <!-- content column -->
    <LinearLayout android:id="@+id/frame_content" android:orientation="vertical"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_marginLeft="32dp" android:layout_marginRight="32dp" />

</LinearLayout>

The Content Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:foo="http://schemas.android.com/apk/res/com.foo"
    android:id="@+id/content_panel" android:orientation="vertical"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <com.foo.view.VideoChooser android:id="@+id/vchShareVids"
        foo:prompt_text="@string/prompt_share_vid" foo:prompt_size="16dp"
        foo:preview_height="80dp"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_marginBottom="12dp" android:hapticFeedbackEnabled="true" />
    <com.foo.view.ContactChooser android:id="@+id/cchRecipients"
        foo:prompt_text="@string/prompt_share_email" foo:prompt_size="16dp"
        foo:preview_lines="3" foo:dialog_title="Pretend you are picking contacts"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_marginBottom="12dp" android:hapticFeedbackEnabled="true" />
    <com.foo.view.TextChooser android:id="@+id/tchDescription"
        foo:prompt_text="@string/prompt_share_description" foo:prompt_size="16dp"
        foo:preview_lines="1" foo:dialog_title="@string/title_msg_chooser_dlg"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_marginBottom="12dp" android:hapticFeedbackEnabled="true" />

    <CheckBox android:id="@+id/chkReshare" android:text="@string/prompt_reshare"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:checked="true" android:hapticFeedbackEnabled="true" />
    <Button android:id="@+id/btnSend" android:text="@string/btn_send"
        android:layout_width="@dimen/btn_width" android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" android:hapticFeedbackEnabled="true" />

</LinearLayout>

Activity Base Class onCreate():

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.common_frame);
}

Activity Implementation onCreate():

@Override
protected void onCreate(Bundle pState)
{
    super.onCreate(pState);
    load_content_view(R.layout.content_layout);

    ViewGroup tLayout = (ViewGroup)findViewById(R.id.content_panel);

    // These all return null
    mCchVideo = (ContentChooser)tLayout.findViewById(R.id.vchShareVids);
    mCchContact = (ContentChooser)tLayout.findViewById(R.id.cchRecipients);
    mCchDescription = (ContentChooser)tLayout.findViewById(R.id.tchDescription);

    // These return valid references
    mChkReshare = (CheckBox)findViewById(R.id.chkReshare);
    mBtnSend = (Button)findViewById(R.id.btnSend);

    // ...
}

protected void load_content_view(int pResId)
{
    LinearLayout tColumn = (LinearLayout)findViewById(R.id.frame_content);
    getLayoutInflater().inflate(pResId, tColumn);
}
like image 219
Ionoclast Brigham Avatar asked Dec 04 '22 19:12

Ionoclast Brigham


1 Answers

I had a similar problem and the solution for mine was to make sure the constructor of the custom widget calls

super(context, attrs); 

My constructor didn't pass attrs to super and thus the view id was messed up and the findviewbyId returned null.

like image 114
Zachary Moshansky Avatar answered May 22 '23 14:05

Zachary Moshansky