276

首先:是的,我阅读了有关该主题的所有其他主题。不仅是来自这个网站的那些......(你看,我有点沮丧)

它们中的大多数都带有使用建议,android:id而不仅仅是id在 XML 文件中。我做到了。

我从其他人那里了解到,这View.findViewByIdActivity.findViewById. 我也处理过。

在我的location_layout.xml中,我使用:

<FrameLayout .... >
    <some.package.MyCustomView ... />

    <LinearLayout ... >
        <TextView ...
            android:id="@+id/txtLat" />
        ...
    </LinearLayout>
</FrameLayout>

在我的活动中,我这样做:

...
setContentView( R.layout.location_layout );

在我的自定义视图类中:

... 
TextView tv = (TextView) findViewById( R.id.txtLat );

返回null这样做,我的 Activity 工作正常。所以也许是因为Activity.findViewByIdView.findViewById差异。所以我在本地存储了传递给海关视图构造函数的上下文并尝试了:

...
TextView tv = (TextView) ((Activity) context).findViewById( R.id.txtLat );

这也返回了null

然后,我将自定义视图更改为扩展,并将其更改为让成为我的自定义视图的直接子级,以便ViewGroup应该按预期工作。惊喜:它没有解决任何问题。Viewlocation_layout.xmlTextViewView.findViewById

那么我到底做错了什么?

我会很感激任何评论。

4

31 回答 31

292

返回 null

可能是因为你打电话太早了。等到onFinishInflate()这是一个示例项目,演示了View访问其内容的自定义。

于 2010-07-16T12:07:30.310 回答
154

可能,您在打电话findViewById之前先打电话setContentView?如果是这种情况,请尝试在调用findViewById 之后调用setContentView

于 2011-11-17T09:33:48.373 回答
105

确保您没有针对不同屏幕密度的多个版本的布局。我在向现有布局添加新 id 但忘记更新 hdpi 版本时遇到过这个问题。如果您忘记更新布局文件的所有版本,它将适用于某些屏幕密度,但不适用于其他屏幕密度。

于 2011-11-05T04:06:02.183 回答
34

如果您在自定义视图中调用错误的超级构造函数,则 FindViewById 可以为 null。ID 标签是 attrs 的一部分,因此如果忽略 attrs,则会删除 ID。

这是错误的

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context);
}

这是对的

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}
于 2015-06-02T17:57:35.537 回答
18

除了其他地方提到的经典原因之外:

  • 确保你之前打过setContentView()电话findViewById()
  • 确保id你想要的在你给的视图或布局中setContentView()
  • 确保id不会在不同的布局中意外重复

我在标准布局中找到了一个自定义视图,这与文档背道而驰:

理论上,您可以创建自定义视图并将其添加到布局中(参见此处)。但是,我发现在这种情况下,有时该id属性适用于布局中的所有视图,自定义视图除外。我使用的解决方案是:

  1. 将每个自定义视图替换为FrameLayout具有与您希望自定义视图相同的布局属性的 。给它一个适当的id,说frame_for_custom_view
  2. onCreate

    setContentView(R.layout.my_layout);
    FrameView fv = findViewById(R.id.frame_for_custom_layout);
    MyCustomView cv = new MyCustomView(context);
    fv.addView(cv);
    

    它将自定义视图放入框架中。

于 2014-12-20T09:06:51.893 回答
15

就我而言,我的项目中有 2 个活动,main.xml并且main2.xml. 从一开始,main2它就是 的副本main,一切运行良好,直到我添加了新TextViewmain2,所以它R.id.textview1可用于应用程序的其余部分。然后我尝试通过标准调用来获取它:

TextView tv = (TextView) findViewById( R.id.textview1 );

它始终为空。事实证明,在onCreate构造函数中我实例化main2的不是 ,而是另一个。我有:

setContentView(R.layout.main);

代替

setContentView(R.layout.main2);

我到达这里后,在网站上注意到了这一点。

于 2013-01-14T15:04:49.000 回答
10
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }
于 2014-06-18T00:24:22.990 回答
6

使用 ExpandableListView 并根据其标题遇到此问题的人的答案。

作为 ExpandableListView 实现的一部分,我尝试在我的子视图和组视图中使用 TextViews 时遇到此错误。

您可以在 getChildView() 和 getGroupView() 方法的实现中使用类似以下的内容。

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_layout, null);
        }

我在这里找到了这个。

于 2012-01-23T22:25:25.057 回答
6

FWIW,我没有看到有人以与我需要的方式完全相同的方式解决了这个问题。编译时没有抱怨,但我在运行时得到一个空视图,并以正确的顺序调用事物。即 setContentView( )之后的 findViewById()。问题原来是我的视图是在 content_main.xml 中定义的,但是在我的 activity_main.xml 中,我缺少这一条语句:

<include layout="@layout/content_main" />

当我将它添加到 activity_main.xml 时,不再有 NullPointer。

于 2016-07-09T02:19:00.320 回答
5

我对 Android/Eclipse 很陌生,我错误地将 UI 内容添加到activity_main.xml而不是fragment_main.xml. 我花了几个小时才弄清楚...

于 2014-04-21T20:03:14.623 回答
3

我有同样的问题。我正在使用第三方库,它允许您覆盖他们的 GridView 适配器并为每个 GridView 单元格指定自己的布局。

我终于意识到发生了什么。Eclipse 仍在为 GridView 中的每个单元格使用库的布局 xml 文件,尽管它没有给出任何指示。在我的自定义适配器中,它表明它正在使用我自己项目中的 xml 资源,即使在运行时它不是。

所以我所做的是确保我的自定义 xml 布局和 id 与仍在库中的那些不同,清理了项目,然后它开始读取我项目中正确的自定义布局。

简而言之,如果您要覆盖第三方库的适配器并指定您自己的布局 xml 供适配器使用,请务必小心。如果项目中的布局与库中的布局具有相同的文件名,那么您可能会遇到一个非常难以发现的错误!

于 2014-07-16T16:09:31.473 回答
3

在我的特殊情况下,我试图向 ListView 添加页脚。onCreate() 中的以下调用返回 null。

TextView footerView = (TextView) placesListView.findViewById(R.id.footer);

将其更改为膨胀页脚视图而不是通过 ID 查找它解决了这个问题。

View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer_view, null, false);
于 2015-03-29T14:41:32.787 回答
3

只是想在这里提出我的具体案例。可能会帮助下线的人。

我在我的 Android UI XML 中使用该指令,如下所示:

父视图:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:visibility="gone" />

子视图(retry_button):

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/retry"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

.findViewById(R.id.retry) 将始终返回 null。但是,如果我将 ID 从子视图移动到包含标记中,它就会开始工作。

固定父母:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:id="@+id/retry"
        android:visibility="gone" />

固定孩子:

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">
于 2016-06-15T17:54:05.793 回答
2

就我而言,我使用的是 ExpandableListView 并且我已经设置了android:transcriptMode="normal". 这导致可扩展组中的几个孩子消失了,当我使用滚动列表时,我曾经得到 NULL 异常。

于 2012-11-26T10:44:28.503 回答
2

对我来说,我有两个用于同一活动的 xml 布局——一个是纵向模式,一个是横向模式。当然,我在横向 xml 中更改了对象的 id,但忘记在纵向版本中进行相同的更改。确保如果您更改一个,您对另一个 xml 执行相同的操作,否则在您运行/调试它并且它无法找到您没有更改的 id 之前您不会收到错误。哦,愚蠢的错误,你为什么要这样惩罚我?

于 2014-01-27T14:48:48.403 回答
2

从布局资源中设置活动内容。即,setContentView(R.layout.basicXml);

于 2014-06-26T09:49:51.370 回答
2

除了上述解决方案之外,您还确保
tools:context=".TakeMultipleImages" 布局中的 mainfest.xml 文件中的值相同:
android:name=".TakeMultipleImages"对于相同的活动元素。使用复制和粘贴创建新活动时会发生

于 2015-03-30T08:48:50.167 回答
2

我有同样的问题,但我认为它值得与你们分享。如果您必须在自定义布局中查找ViewById,例如:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

您无法在构造函数中获取视图。在视图膨胀后,您应该调用 findViewById。它们是您可以覆盖的方法onFinishInflate

于 2015-08-31T06:46:03.607 回答
2

我的情况与上述不同,没有解决方案。我认为我的观点过于深入布局层次结构。我将它向上移动了一层,它不再为空。

于 2017-11-26T19:20:48.487 回答
1

在我的情况下,我夸大了布局,但子视图返回 null。最初我有这个:

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

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) findViewById(R.id.pbListviewFooter);
    tvText = (TextView) findViewById(R.id.tvListviewFooter);
    ...
}

但是,当我将其更改为以下内容时,它起作用了:

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

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) footerView.findViewById(R.id.pbListviewFooter);
    tvText = (TextView) footerView.findViewById(R.id.tvListviewFooter);
    ...
}

关键是要专门引用已经膨胀的布局以获得子视图。也就是说,添加footerView

  • footerView .findViewById...
于 2015-01-09T06:35:27.137 回答
1

膨胀布局!(其中包含 id)

在我的情况下 findViewById() 返回 null,因为写入元素的布局没有膨胀......

例如。片段布局.xml

<ListView
android:id="@+id/listview">

findViewById(R.id.listview) 返回 null,因为我还没有完成 inflater.inflate(R.layout.fragment_layout, ..., ...); 在它之前。

希望这个答案对你们中的一些人有所帮助。

于 2015-10-24T20:52:51.277 回答
1

它对我来说崩溃了,因为我的活动 id 中的一个字段与另一个活动中的 id 匹配。我通过提供一个唯一的 ID 来修复它。

在我的 loginActivity.xml 密码字段 id 是“密码”。在我的注册活动中,我只是通过提供 id r_password 来修复它,然后它返回非空对象:

password = (EditText)findViewById(R.id.r_password);
于 2018-12-13T02:09:25.033 回答
0

根据我的经验,这似乎也可能发生在您的代码在 OnDestroyView 之后调用时(当片段位于后台堆栈时)。如果您正在从 BroadCastReceiver 的输入更新 UI,您应该检查是否是这种情况.

于 2014-04-11T15:49:50.130 回答
0

如果您在 Fragment 中,findViewById 也可以返回 null。如此处所述:片段中的 findViewById

您应该调用 getView() 以返回片段内的顶级视图。然后你可以找到布局项(按钮、文本视图等)

于 2016-10-27T02:26:16.850 回答
0

在我的例子中,当我将调用从父对象移动到由父对象实例化的适配器对象时,findViewById 返回 null。在尝试了此处列出的技巧但没有成功后,我将 findViewById 移回父对象,并在适配器对象的实例化期间将结果作为参数传递。例如,我在父对象中这样做:

 Spinner hdSpinner = (Spinner)view.findViewById(R.id.accountsSpinner);

然后我在创建适配器对象时将 hdSpinner 作为参数传递:

  mTransactionAdapter = new TransactionAdapter(getActivity(),
        R.layout.transactions_list_item, null, from, to, 0, hdSpinner);
于 2018-07-27T05:24:20.793 回答
0

当我尝试为ListView.

我只是通过这样做解决了它:

public View getView(int i, View view, ViewGroup viewGroup) {

    // Gets the inflater
    LayoutInflater inflater = LayoutInflater.from(this.contexto);

    // Inflates the layout
    ConstraintLayout cl2 = (ConstraintLayout) 
    inflater.inflate(R.layout.custom_list_view, viewGroup, false);

    //Insted of calling just findViewById, I call de cl2.findViewById method. cl2 is the layout I have just inflated. 
     TextView tv1 = (TextView)cl2.findViewById(cl2);
于 2019-03-13T10:25:23.800 回答
0

调试和发现问题的方法:

  • 注释掉您活动中的所有 findViewById。
  • 注释掉除 onCreate 和 setContentView 之外的所有内容
  • 运行项目,看看是否设置了任何布局

就我而言,我在我的应用程序模块和库模块中都使用了 activity_main.xml。因此,当我执行上述步骤时,不是我在库中设计的布局,而是应用模块内部的布局被夸大了。

所以我把activity_main.xml文件名改成了activity_main_lib.xml。

因此,请确保您的整个项目中没有任何重复的布局名称

于 2020-05-31T10:48:37.183 回答
0

我的问题是我有两个具有相同文件名的布局activity_main.xml。(布局在不同的库中,但在同一个应用程序中)通过将其中一个重命名为唯一名称解决了这个问题。

于 2022-02-03T15:00:17.003 回答
0

对我来说,它返回 null 因为给定的控件是(以编程方式)隐藏的。当我设置条件仅在控件可见时调用 findViewByID(id) 时,它又开始工作了。

于 2022-02-24T08:38:12.660 回答
-1

我的解决方法是清理项目。

于 2016-05-24T17:51:08.753 回答
-1

我已经尝试了以上所有方法都没有工作..所以我不得不让我的ImageView 静态 public static ImageView texture;然后texture = (ImageView) findViewById(R.id.texture_back);,我认为这不是一个好方法,但这确实适用于我的情况:)

于 2017-10-06T06:05:39.413 回答