findViewById(int) 对于自定义视图返回 null,但对于 Android 内置视图则不返回 null

发布于 2024-12-10 08:37:10 字数 5413 浏览 0 评论 0原文

情况:我的布局中有一些自定义组件。我有一个通用布局框架,我将其加载到 Activity 基类的 onCreate() 中,然后使用 inflater 在我的实现中加载内容布局,将根设置为主布局的内容列。

问题:当我获取对视图的引用以实际提取用户的输入时,Activity.findViewById() 返回null。这也许是一个线索,我在布局中的复选框和按钮不返回 null;我得到了对该小部件的有效引用。

我尝试过的事情:我知道我正在正确加载和膨胀布局 xml,因为所有内容都会显示出来,并且可以通过 ID 找到同一布局中的标准视图。我可以与我的视图进行交互,并将内容放入其中以及所有内容中,但我无法在代码中引用它们。

我曾多次尝试清理该项目。 R.id 是最新的。

我检查了控制台和错误日志,没有报告 UI/XML 错误。

我尝试获取为此活动加载的内容的根布局的句柄,并调用 View.findViewById() 来获取我的引用,这也返回 null 。如果我检查调试器中的布局,我可以深入了解并在 mChildren 中找到我的视图。

也许另一条线索:

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

将产生以下输出:

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

分配给视图的ID与R.id中的ID不匹配!为什么会这样呢?我知道它正在加载 android:id 属性,否则它将是 -1 (View.NO_ID)。

通用布局框架:

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

内容布局:

<?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 基类 onCreate():

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

Activity 实现 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);
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撩人痒 2024-12-17 08:37:10

我有一个类似的问题,我的解决方案是确保自定义小部件调用的构造函数

super(context, attrs); 

我的构造函数没有将 attrs 传递给 super,因此视图 id 被搞乱,findviewbyId 返回 null。

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.

北方的巷 2024-12-17 08:37:10

如果没有实际来源,很难发现问题。我根据您的帖子及其完整作品创建了示例项目。
我相信有一个非常简单的错误,你会发现它的。
如果你愿意,你可以尝试一下

It's very difficult to find problem without actual sources. I've created sample project based on your posts and its fully works.
I believe that there is very simple mistake and you'll find it.
If you want, you may try it

谁的年少不轻狂 2024-12-17 08:37:10

是的...我是个白痴。 View 当然设置了正确的 ID,然后我的一个 init 方法返回并破坏了它。

捂脸

Yeah... I'm an idiot. View was of course setting the correct ID, and then one of my init methods went back and clobbered it.

facepalm

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文