findViewByID返回null


250

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

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

我从其他人那里了解到,该方法与的View.findViewById工作原理有所不同Activity.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.findViewById和的View.findViewById差异。因此,我将传递给上下文的上下文存储在本地的海关视图构造函数中并尝试:

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

这也回来了null

然后,我改变了我的自定义视图扩展ViewGroup,而不是View和改变location_layout.xmlTextView我的自定义视图的直接子,从而使View.findViewById应该工作的设想。惊喜:它什么都没解决。

那么,我到底在做什么错呢?

我将不胜感激。


6
如果项目也损坏,可能会发生这种情况。我固定它通过清洁项目
Pacerier

1
通过了错误的上下文视图,谢谢
izzy 2015年

1
@Pacerier谢谢。解决了我的问题。我开始讨厌Xamarin中的android编程)
Artiom

@Pacerier“清洁项目”也解决了我的问题。似乎Dropbox破坏了项目。
Kohki Mametani

Answers:


270

返回null

可能是因为您为时过早。等到onFinishInflate()这是一个示例项目,展示了自定义View访问其内容的方法。


67
我的天啊!不能相信我花了几天时间在如此琐碎的事情上。我将setContentView()移到了findViewById()调用之上,但他没有欺骗。谢谢!
agentcurry 2012年

2
@CommonsWare那是正确的项目吗?我在github.com/commonsguy/cw-advandroid/tree/master/Animation/的任何地方都看不到onFinishInflate
likejudo 2015年

1
@likejiujitsu:可能是在2010年。我已将链接更新为具有的新项目onFinishInflate()
CommonsWare

3
我在findViewById之前调用了setContentView,但它仍然为null。我引用的是EditText
Neon Warge,2013年

1
始终链接到固定的GitHub提交(例如github.com/commonsguy/cw-omnibus/tree/…),并且从不删除存储库或变基;-)
Ciro Santilli郝海东冠状病六四事件法轮功

145

可能是您在打电话findViewById之前打电话setContentView?如果是这样的情况下,尝试调用findViewById 调用setContentView


1
这样容易犯的错误,但不幸的是,这就是我所做的。调试器没有用,因为它说错误是在我的新意图行而不是在我正在调用的实际新活动中发生的。谢谢!
edude05'2013-4-13

6
其实我有这个错误,因为我在调用setContentView时指向错误的视图……不幸的是,编译器没有捕获这种类型的错误。
HeatfanJohn

是的,我误删除了setContentView,并且不明白为什么我的程序开始崩溃。
罗恩·费斯廷格

100

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


8
谢谢!就是这样 (就我而言,我有多个版本用于不同的Android版本)。尽管我在每个布局文件的顶部和底部都添加了巨大的注释,但我一直都忘了它。我希望编译器在发生这种情况时会发出错误或重大警告。
tiktak

叮叮叮,非常感谢!让我的大脑在这个大笑上弯曲
扎克

21

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

这是错的

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

这是对的

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

1
非常感谢你,先生!我很粗心,我什至怀疑我的IDE出了点问题。见到您的答案真幸运。
EffectiveMatrix

创建自定义视图时,我犯了这个错误。谢谢,repkap11。
Andrew F.

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

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


14

除了经典原因外,其他地方也提到过:

  • 请确保您已被称为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);

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


这对我有所帮助:“确保所需的ID在给setContentView()的视图或布局中”。但是,当它是子视图时该怎么办?尝试获取父视图,然后执行parentView.findById(),但它仍返回null
NaturalBornCamper

@naturalborncamper,如果您用示例代码发布一个单独的问题,我来看看。
尼尔·汤森

谢谢Neil,我已经发布了,有人指出了一种更好的方法,尽管它并不能完全按照
预期方式

9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }

6

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

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

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

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

我在这里找到的。


5

我是Android / Eclipse的新手,所以我误将UI内容添加到activity_main.xml而不是中fragment_main.xml。花了我几个小时才弄清楚...


5

FWIW,我看不到有人用我需要的方式解决了这个问题。编译时没有任何抱怨,但是我在运行时得到了一个空视图,并以正确的顺序调用事物。也就是说, setContentView()之后找到 findViewById ()。问题表明,我的视图是在content_main.xml中定义的,但是在我的activity_main.xml中,我缺少以下一条语句:

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

当我将其添加到activity_main.xml时,不再需要NullPointer。


复制粘贴片段的问题在于,您有时会忘记更改某些内容……是使其中的一个膨胀的正确布局。谢谢!
PabloQuemé18年

3

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

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

因此,我要做的是确保我的自定义xml布局和ID与仍位于库中的那些不同,清理项目,然后开始读取项目中正确的自定义布局。

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


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

2

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


2

对我来说,我有两种用于同一活动的xml布局-一种是纵向模式,另一种是横向模式。当然,我已经在Landscape xml中更改了对象的ID,但是忘记了在Portrait版本中进行了相同的更改。确保如果您更改一个对另一个xml进行相同的操作,或者直到您运行/调试它并且找不到您未更改的id时,您不会收到错误。哦,愚蠢的错误,你为什么要惩罚我?



2

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


2

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

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

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


2

只是想把我的具体情况放在这里。可能会帮助某人。

我在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从子视图移到include标记中,它将开始工作。

固定父母:

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

2

我的情况与上述情况不同,没有解决方案。我认为我的观点对布局层次结构太深了。我将其上移了一层,现在它不再为null了。


我有同样的问题,也可以找到更高的级别。.这很烦人,我想知道为什么会这样,因为我无法按我的意愿制作菜单
NaturalBornCamper

很好的布局层次结构是反模式,几乎总是有一个更干净的解决方案。您是在谈论工具栏或导航抽屉中的溢出菜单吗?
Deividas Strioga

导航抽屉中,我实际上已经发布了另一个问题,除了在组内添加菜单项不起作用外,仅将其添加到所有项的末尾即可: stackoverflow.com/questions/47955376/…–
NaturalBornCamper

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

0

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


0

插入布局!(包含ID)

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

例如。fragment_layout.xml

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

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

希望这个答案对你们所有人有所帮助。



0

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

您应该调用getView()以返回Fragment内的顶级View。然后,您可以找到布局项目(按钮,文本视图等)


0

我已经尝试了以上所有方法,但没有任何效果。.所以我不得不将ImageView 设为静态public static ImageView texture;,然后texture = (ImageView) findViewById(R.id.texture_back);,我认为这不是一个好方法,但这确实适合我的情况:)


抱歉,我认为静态视图不是一个好主意
vuhung3990

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

0

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

在我的loginActivity.xml密码字段中,ID为“ password”。在我的注册活动中,我只是通过提供id r_password对其进行了修复,然后它返回的不是null对象:

password = (EditText)findViewById(R.id.r_password);

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

0

调试和发现问题的方法:

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

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

因此,我将activity_main.xml文件名更改为activity_main_lib.xml。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.