【问题标题】:findViewById() returns null for custom component in layout XML, not for other componentsfindViewById() 为布局 XML 中的自定义组件返回 null,而不是其他组件
【发布时间】:2010-12-14 01:50:10
【问题描述】:

我有一个res/layout/main.xml,包括这些元素和其他元素:

<some.package.MyCustomView android:id="@+id/foo" (some other params) />
<TextView android:id="@+id/boring" (some other params) />

在我的 Activity 的 onCreate 中,我这样做:

setContentView(R.layout.main);
TextView boring = (TextView) findViewById(R.id.boring);
// ...find other elements...
MyCustomView foo = (MyCustomView) findViewById(R.id.foo);
if (foo == null) { Log.d(TAG, "epic fail"); }

成功找到其他元素,但 foo 返回 null。 MyCustomView 有一个构造函数 MyCustomView(Context c, AttributeSet a) 和一个 Log.d(...) 在构造函数的末尾成功地出现在“史诗失败”之前的 logcat 中。

为什么foo 为空?

【问题讨论】:

    标签: xml android layout


    【解决方案1】:

    因为在构造函数中,我有super(context) 而不是super(context, attrs)

    有道理,如果您不传递属性,例如 id,那么视图将没有 id,因此无法使用该 id 找到。 :-)

    【讨论】:

    • 另外,像(MyCustomView) foo = findViewById(R.id.foo); 这样的行不应该是MyCustomView foo = (MyCustomView) findViewById(R.id.foo);吗?
    • 有同样的问题,在我的情况下,我忘记了 setContentView().. XD
    • 在 vogella.com 上有一个很好的例子:vogella.com/articles/AndroidCustomViews/article.html
    • 另外,如果您有多个构造函数,您需要将所有 super() 方法更新为正确的方法。
    • 当我看到好的 'ol findViewById() 返回 null 时,我开始心脏病发作......你节省了我的时间!谢谢!
    【解决方案2】:

    我遇到了同样的问题,因为在我的自定义视图中我已经覆盖了构造函数,但是调用了没有attrs 参数的超级构造函数。 (这是一个复制/粘贴错误。)

    我之前的构造函数版本:

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

    现在我有:

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

    这行得通!

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题。我的错误是:我写了

              LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              View layout=inflater.inflate(R.layout.dlg_show_info, null);
              alertDlgShowInfo.setView(layout);
              TableRow trowDesc=(TableRow)findViewById(R.id.trowDesc);
      

      当我使用充气器从 XML 文件“加载”视图时,最后一行是错误的。为了解决它,我不得不写:

      TableRow trowDesc=(TableRow)layout.findViewById(R.id.trowDesc);
      

      我写了我的解决方案,以防有人遇到同样的问题。

      【讨论】:

        【解决方案4】:

        似乎有多种原因。我只是在 Eclipse 中使用“Clean ...”来解决类似的问题。 (FindViewByID 之前工作过,但由于某种原因开始返回 null。)

        【讨论】:

        • 显然,根本问题是 R.java ID 以某种方式损坏或可能未更新。我不仅在 ID 上注意到了这一点,而且在其他情况下也注意到了这一点,例如TextView 等中显示的字符串错误。不过,我真的不知道为什么会发生这种情况。
        【解决方案5】:

        同样的问题,但不同的解决方案:我没有打电话

        setContentView(R.layout.main)
        

        在我试图找到here 中所述的视图之前

        【讨论】:

        • 如果您在其他视图而不是当前相关视图上获取元素,我认为这是解决方案。
        【解决方案6】:

        如果您有多个布局版本(取决于屏幕密度、SDK 版本),请确保所有布局版本都包含您要查找的元素。

        【讨论】:

          【解决方案7】:

          在我的例子中 findViewById 返回 null 因为我的自定义视图在主 XML 中看起来像这样:

                  <com.gerfmarquez.seekbar.VerticalSeekBar  
                      android:id="@+id/verticalSeekBar"
                      android:layout_width="wrap_content" 
                      android:layout_height="fill_parent" 
                      />
          

          我发现当我添加 xmlns 的东西时,它的工作原理是这样的:

                  <com.gerfmarquez.seekbar.VerticalSeekBar  
                      xmlns:android="http://schemas.android.com/apk/res/android"
                      android:id="@+id/verticalSeekBar"
                      android:layout_width="wrap_content" 
                      android:layout_height="fill_parent" 
                      />
          

          【讨论】:

            【解决方案8】:

            确保setContentView(R.layout.main) 语句在findViewById(...) 语句之前调用;

            【讨论】:

              【解决方案9】:

              对我来说,当我将 res 文件夹添加到项目设置中 Java 构建路径中的 Source 时,问题就解决了。

              【讨论】:

                【解决方案10】:

                不久前,当我通过布局 XML 添加自定义视图时,我遇到了同样的问题 然后尝试在应用程序的其他地方附加回调...

                我创建了一个自定义视图并将其添加到我的“layout_main.xml”中

                public class MUIComponent extends SurfaceView implements SurfaceHolder.Callback {
                    public MUIComponent (Context context, AttributeSet attrs ) {
                        super ( context, attrs );
                    }
                    // ..
                }
                

                在主 Activity 中,我想附加一些回调并从 XML 中获取对 UI 元素的引用。

                public class MainActivity extends Activity {
                
                    @Override
                    protected void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                
                        // ...
                
                        MUIInitializer muiInit = new MUIInitializer();
                        muiInit.setupCallbacks(this);
                        muiInit.intializeFields(this);
                    }       
                }
                

                初始化器并没有做任何花哨的事情,但它试图对自定义视图 (MUIComponent) 进行任何更改 或其他非自定义 UI 元素根本没有出现在应用程序中。

                public class MUIInitializer {
                
                    // ...
                
                    public void setupCallbacks ( Activity mainAct ) {
                
                
                        // This does NOT work properly
                        // - The object instance returned is technically an instance of my "MUICompnent" view
                        //   but it is a *different* instance than the instance created and shown in the UI screen
                        // - Callbacks never get triggered, changes don't appear on UI, etc.
                        MUIComponent badInst = (MUIComponent) mainAct.findViewById(R.id.MUIComponent_TESTSURF);
                
                
                        // ...
                        // This works properly
                
                        LayoutInflater inflater = (LayoutInflater) mainAct.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                        View inflatedLayout = inflater.inflate ( R.layout.activity_main, null );
                
                        MUIComponent goodInst = (MUIComponent) inflatedLayout.findViewById(R.id.MUIComponent_TESTSURF);
                
                
                        // Add callbacks
                        // ...
                    }
                
                }
                

                “badInst”和“goodInst”的区别是:

                • badInst 使用 Activity 的 findViewByID
                • goodInst 膨胀布局并使用膨胀的布局进行查找

                【讨论】:

                • 注意到文森特有相同的解决方案......他的答案更短......改为+1 :)
                【解决方案11】:

                这发生在我的 Wear 自定义组件上,但这是一条通用的建议。如果您使用的是 Stub(例如我使用的是 WatchViewStub),您不能只在任何地方调用 findViewById()。存根中的所有内容都必须首先膨胀,这不仅仅发生在setContentView() 之后。因此,你应该写这样的东西来等待它发生:

                protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.activity_wear);
                    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
                    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
                        @Override
                        public void onLayoutInflated(WatchViewStub stub) {
                            myCustomViewInst = (MyCustomView) findViewById(R.id.my_custom_view);
                            ...
                

                【讨论】:

                  【解决方案12】:

                  我的问题是一个错字。我写的是android.id(点)而不是android:id。 :P

                  显然我的自定义组件 xml 中没有语法检查。 :(

                  【讨论】:

                    【解决方案13】:

                    遇到同样的问题。

                    我有几个孩子的布局。从其中一个的构造函数中,我试图(通过使用 context.findViewById)获取对其他孩子的引用。它不起作用,因为第二个孩子在布局中被进一步定义。

                    我已经这样解决了:

                    setContentView(R.layout.main);
                    MyView first = findViewById(R.layout.first_child);
                    first.setSecondView(findViewById(R.layout.second_child));
                    

                    如果孩子的顺序相反也可以,但我想一般应该像上面那样做。

                    【讨论】:

                    • 一般你不应该在View的构造函数中使用findViewById,而是将初始化代码放在OnFinishInflate中?
                    【解决方案14】:

                    当布局的根没有android:id 属性时,findViewById() 方法有时会返回null。用于生成布局 xml 文件的 Eclipse 向导不会自动为根元素生成 android:id 属性。

                    【讨论】:

                      【解决方案15】:

                      在我的情况下,视图在父视图中而不是在我试图调用它的视图中。所以在子视图中我必须调用:

                      RelativeLayout relLayout = (RelativeLayout) this.getParent();
                      View view1 = relLayout.findViewById(R.id.id_relative_layout_search);
                      

                      【讨论】:

                        【解决方案16】:

                        “干净”选项对我有用。

                        就我而言,根本原因是源代码位于网络共享上,而我的工作站和文件服务器没有正确同步,并且偏移了 5 秒。 Eclipse 创建的文件的时间戳是过去的(因为它们是由文件服务器分配的)w.r.t。工作站的时钟,导致 Eclipse 错误地解析生成文件和源文件之间的依赖关系。在这种情况下,“清理”似乎有效,因为它强制完全重建,而不是依赖于错误时间戳的增量构建。

                        一旦我在我的工作站上修复了 NTP 设置,问题就再也没有发生过。如果没有适当的 NTP 设置,它每隔几个小时就会发生一次,因为时钟漂移得很快。

                        【讨论】:

                        • 应将此添加到上述answer 的评论中
                        【解决方案17】:

                        在要注意的答案中添加另一个小错误:

                        检查您是否真的在编辑正确的布局 XML 文件...

                        【讨论】:

                          【解决方案18】:

                          我遇到了同样的问题,因为我忘记更新所有布局文件夹中的视图 ID。

                          【讨论】:

                            猜你喜欢
                            • 2019-09-09
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-03-20
                            • 2011-04-21
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多