【问题标题】:findViewByID returns nullfindViewByID 返回 null
【发布时间】:2011-03-16 22:18:39
【问题描述】:

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

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

我从其他人那里了解到,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 工作正常。所以可能是因为 Activity.findViewByIdView.findViewById 的差异。所以我将传递给海关视图构造函数的上下文存储在本地并尝试:

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

这也返回了null

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

那我到底做错了什么?

我将不胜感激。

【问题讨论】:

  • 如果项目也损坏了,可能会发生这种情况。我通过清理项目来修复它
  • 通过错误的上下文视图谢谢
  • @Pacerier 谢谢。这解决了我的问题。我开始讨厌 Xamarin 中的 android 编程)
  • @Pacerier "Clean project" 也解决了我的问题。看来 Dropbox 破坏了项目。

标签: android android-view


【解决方案1】:

返回 null

可能是因为您调用它为时过早。等到onFinishInflate()Here is a sample project 演示了一个自定义的 View 访问其内容。

【讨论】:

  • 天啊!不敢相信我会花几天时间在如此微不足道的事情上。我将 setContentView() 移到了 findViewById() 调用之上,这成功了。谢谢!
  • @CommonsWare 它是正确的项目吗?我在github.com/commonsguy/cw-advandroid/tree/master/Animation/… 的任何地方都没有看到 onFinishInflate
  • @likejiujitsu:可能早在 2010 年就有这种情况了。我已经更新了指向具有 onFinishInflate() 的新项目的链接。
  • 我在 findViewById 之前调用了我的 setContentView,但它仍然为空。我正在引用一个 EditText
  • 始终链接到已修复的 GitHub 提交(例如 github.com/commonsguy/cw-omnibus/tree/… ),从不删除 repos 或 rebase ;-)
【解决方案2】:

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

【讨论】:

  • 这样一个容易犯的错误,但不幸的是这就是我所做的。调试器没有用,因为它说错误出现在我的新意图行而不是我调用的实际新活动中。谢谢!
  • 其实我有这个错误,因为我调用 setContentView 指向错误的视图......不幸的是编译器没有捕捉到这种类型的错误。
  • 是的,我误删了setContentView,不明白为什么我的程序开始崩溃了。
【解决方案3】:

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

【讨论】:

  • 谢谢!就是这样。 (在我的情况下,我有多个版本用于不同的 Android 版本)。尽管我在每个布局文件的顶部和底部都放了一个巨大的注释,但我一直忘记它。如果发生这种情况,我希望编译器会发出错误或严重警告。
  • 叮叮叮,非常感谢!在这个大声笑上弯曲我的大脑
  • 我花了 1.5 个工作日来解决这个问题。只有你的解释解决了我的问题(不是 setContentView / findViewById 序列问题,因为许多 Google 结果告诉我)谢谢!!
【解决方案4】:

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

这是错误的

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

这是正确的

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

【讨论】:

  • 非常感谢您,先生!我太粗心了,我什至怀疑我的 IDE 有问题。能得到你的答案真是太幸运了。
  • 我在创建自定义视图时犯了这个错误。谢谢你,repkap11。
  • 你为我节省了很多时间!
  • 老兄,我不得不说谢谢你,像我这样的人不可能专门解决这个问题,因为没有日志或错误。
【解决方案5】:

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

  • 确保您在findViewById() 之前调用过setContentView()
  • 确保您想要的id 在您提供给setContentView() 的视图或布局中
  • 确保id 不会在不同布局中意外重复

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

理论上,您可以创建自定义视图并将其添加到布局中 (see here)。但是,我发现在这种情况下,有时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 如果您使用示例代码发布一个单独的问题,我会看看它。
  • 谢谢尼尔,我已经发布了,有人指出了一个更好的方法来做到这一点,虽然它不能完全按照它应该的方式工作,所以我不得不使用不同的策略:stackoverflow.com/questions/47955376/…
【解决方案6】:

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

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

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

setContentView(R.layout.main);

而不是

setContentView(R.layout.main2);

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

【讨论】:

    【解决方案7】:
        @Override
    protected void onStart() {
             // use findViewById() here instead of in onCreate()
        }
    

    【讨论】:

      【解决方案8】:

      对于那些使用 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);
              }
      

      我找到了这个here

      【讨论】:

        【解决方案9】:

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

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

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

        【讨论】:

        • 复制粘贴 Fragment 的问题是您有时会忘记更改某些内容……这是对其中之一进行膨胀的正确布局。谢谢!
        【解决方案10】:

        我是 Android/Eclipse 的新手,我错误地将 UI 内容添加到 activity_main.xml 而不是 fragment_main.xml。我花了几个小时才弄明白...

        【讨论】:

          【解决方案11】:

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

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

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

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

          【讨论】:

            【解决方案12】:

            在我的特殊情况下,我试图向 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);
            

            【讨论】:

              【解决方案13】:

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

              我在我的 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">
              

              【讨论】:

                【解决方案14】:

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

                【讨论】:

                  【解决方案15】:

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

                  【讨论】:

                    【解决方案16】:

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

                    【讨论】:

                      【解决方案17】:

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

                      【讨论】:

                        【解决方案18】:

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

                        public class MiniPlayerControllBar extends LinearLayout {
                            //code
                        }
                        

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

                        的方法

                        【讨论】:

                          【解决方案19】:

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

                          【讨论】:

                          • 我有同样的问题,也可以找到更高的级别.. 这很烦人,我想知道为什么会这样,因为我无法按照我的意愿制作菜单
                          • 深布局层次结构是反模式,几乎总是有一个更清洁的解决方案。你是说工具栏上的溢出菜单,还是导航抽屉?
                          • 导航抽屉,实际上我已经发布了另一个问题,除了在组内添加菜单项不起作用,只需将其添加到所有项目的末尾即可:stackoverflow.com/questions/47955376/…
                          【解决方案20】:

                          扩大布局! (其中包含 id)

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

                          例如。 片段布局.xml

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

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

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

                          【讨论】:

                            【解决方案21】:

                            在我的例子中,我夸大了布局,但子视图返回 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...

                            【讨论】:

                              【解决方案22】:

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

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

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

                              【讨论】:

                                【解决方案23】:

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

                                【讨论】:

                                  【解决方案24】:

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

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

                                  【讨论】:

                                    【解决方案25】:

                                    在我的例子中,当我将调用从父对象移动到由父对象实例化的适配器对象时,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);
                                    

                                    【讨论】:

                                      【解决方案26】:

                                      当我尝试为 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);
                                      

                                      【讨论】:

                                        【解决方案27】:

                                        调试和发现问题的方法:

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

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

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

                                        所以确保您的整个项目中没有任何重复的布局名称

                                        【讨论】:

                                          【解决方案28】:

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

                                          【讨论】:

                                            【解决方案29】:

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

                                            【讨论】:

                                              【解决方案30】:

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

                                              【讨论】:

                                                猜你喜欢
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 2016-09-18
                                                • 1970-01-01
                                                相关资源
                                                最近更新 更多