对于布局XML中的自定义组件,对于其他组件,findViewById()返回null


91

我有一个res/layout/main.xml包括以下要素和其他要素:

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

在我的活动的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空?

Answers:


182

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

很有道理,如果您不传入属性(例如id),则视图将没有id,因此无法使用该id查找。:-)


1
总是很高兴能够回答您自己的问题:)确保也将您的问题标记为已接受的答案。
MattC

确实。当SO允许我时将这样做(“您可以在2天内接受自己的回答。”)
克里斯·博伊尔2009年

4
此外,你不应该线条状(MyCustomView) foo = findViewById(R.id.foo);MyCustomView foo = (MyCustomView) findViewById(R.id.foo);
杰里米·洛根

3
遇到同样的问题,在我的情况下,我忘记了setContentView()。XD
Tom Brito 2010年

在vogella.com上有一个很好的例子来做这些事情:vogella.com/articles/AndroidCustomViews/article.html
Wolkenjaeger 2013年

27

我有同样的问题,因为在我的自定义视图中,我重写了构造函数,但调用了超级构造函数withot attrs参数。那就是复制粘贴)

我以前的构造函数版本:

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

我现在有:

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

那行得通!


这里同样的问题。顺便说一句,这也是我的复制粘贴错误。
科特·柯本

同样的事情发生在我身上。关于Stackoverflow的最正确答案。当添加AttributeSet attrs时,一切都很好。
斯皮克扬

我想我们所有人都使用自定义视图查找了同一教程;)这个错误使我进行了0.5小时的毫无意义的调试...
KrwawyKefir

这也对我有用!我为此战斗了很长时间。谢谢!
us_david

18

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

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

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


杜德,你真是个天才。那是我在SO上阅读的所有解决方案中唯一对我
有用的

这也是我的问题。哇,真是...我要花几天的时间自己解决这个问题。谢谢!
poshaughnessy 2012年

18

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


1
显然,潜在的问题是R.java ID以某种方式损坏或可能未更新。我不仅在ID中注意到了这一点,在其他情况下也注意到了这一点,例如在TextView中显示错误的字符串等。不过,我真的不知道为什么会这样。
水母

这给我带来了太久的悲伤-清洁确实为我解决了问题。
Nicholas MT Elliott,

1
确实是清理。哇,真烂!
TimBüthe2011年

11

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

setContentView(R.layout.main)

在我尝试找到此处所述的视图之前


我认为这是解决方案,如果您正在其他视图而不是当前相关视图上获取元素。
StarCub'4

4

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


2

在我的情况下,因为我的自定义视图在主XML中看起来像这样,所以findViewById返回null:

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

2

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


1

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


1

当我通过布局XML添加自定义视图,然后尝试在应用程序中的其他位置附加回调时,我遇到了相同的问题。

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

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

在主活动中,我想附加一些回调并从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使用活动的findViewByID
  • goodInst扩大布局并使用扩大后的布局进行查找

注意到文森特有相同的解决方案...而且他的回答更短... + 1,而不是他的:)
DevByStarlight 2012年

1

发生在我身上的是Wear的自定义组件,但这只是一般性的建议。如果您正在使用存根(例如我正在使用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);
            ...

0

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

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


0

有同样的问题。

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

我已经这样解决了:

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

如果孩子的顺序相反,它也可以工作,但是我想通常应该像上面那样做。


1
通常,您不应findViewById在的构造函数中使用View,而应将初始化代码放入OnFinishInflate?中。
Sanjay Manohar'2

0

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


0

就我而言,该视图位于父视图中,而不是我试图调用的视图中。因此,在子视图中,我必须调用:

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

0

“干净”选项对我有用。

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

一旦我在工作站上修复了NTP设置,问题就再也不会发生。如果没有正确的NTP设置,由于时钟漂移很快,它将每隔几个小时发生一次。


应该在上面答案的注释中添加此内容
Trung Nguyen

0

在要寻找的答案中添加另一个琐碎的错误:

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


0

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

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.