findViewById()为布局XML中的自定义组件返回null,而不是其他组件

时间:2009-11-07 01:26:33

标签: xml android layout

我有res/layout/main.xml包含这些元素和其他元素:

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

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

18 个答案:

答案 0 :(得分:171)

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

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

答案 1 :(得分:22)

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

我以前的构造函数版本:

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

现在我有:

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

这有效!

答案 2 :(得分: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);

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

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

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

答案 3 :(得分:18)

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

答案 4 :(得分:11)

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

setContentView(R.layout.main)

在我尝试找到here

所述的视图之前

答案 5 :(得分:4)

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

答案 6 :(得分:2)

在我的情况下,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" 
            />

答案 7 :(得分:2)

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

答案 8 :(得分:1)

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

答案 9 :(得分: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);
            ...

答案 10 :(得分:1)

当我通过布局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);
    }       
}

initilizer没有做任何花哨的事情,但它尝试对自定义视图进行任何更改(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使布局膨胀并使用膨胀布局进行查找

答案 11 :(得分:0)

'干净'选项对我有用。

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

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

答案 12 :(得分:0)

在我的情况下,视图位于我试图调用它的视图中的父视图中。所以在子视图中我不得不调用:

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

答案 13 :(得分:0)

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

答案 14 :(得分:0)

要在答案中添加另一个微不足道的错误,请注意:

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

答案 15 :(得分:0)

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

答案 16 :(得分:0)

有同样的问题。

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

我已经解决了这个问题:

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

如果孩子的顺序相反,它也会起作用,但我想通常应该如上所述。

答案 17 :(得分:0)

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

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