代码之家  ›  专栏  ›  技术社区  ›  Chris Boyle

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

  •  86
  • Chris Boyle  · 技术社区  · 15 年前

    我有一个 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 返回空值。MyCustomView有一个构造函数 MyCustomView(Context c, AttributeSet a) Log.d(...) 最后,构造函数在“epic fail”之前成功地出现在logcat中。

    18 回复  |  直到 8 年前
        1
  •  186
  •   Chris Boyle    15 年前

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

    有意义的是,如果不传入属性(如id),则视图将没有id,因此无法使用该id查找视图。:-)

        2
  •  28
  •   honk    3 年前

    attrs 参数(这是一个复制/粘贴错误。)

    我以前的构造函数版本:

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

    现在我有:

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

        3
  •  18
  •   Vincent    14 年前

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

            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
  •  18
  •   jellyfish    13 年前

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

        5
  •  11
  •   Daniel    14 年前

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

    setContentView(R.layout.main)
    

    here

        6
  •  4
  •   M.Q.    12 年前

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

        7
  •  2
  •   gerfmarquez    13 年前

            <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
  •  2
  •   Lucifer phtrivier    12 年前

    确保 setContentView(R.layout.main) 之前的声明调用 findViewById(...) 陈述

        9
  •  1
  •   Jiwon Park    14 年前

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

        10
  •  1
  •   DevByStarlight    12 年前

    不久前,当我通过布局和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);
        }       
    }
    

    initilizer没有做任何花哨的事情,只是尝试对自定义视图(MUIComponent)进行任何更改 或其他 非海关

    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”之间的区别是:

    • goodInst对布局进行充气,并使用充气的布局进行查找
        11
  •  1
  •   Stephen Wylie    9 年前

    这发生在我身上,是一个定制的磨损组件,但这是一个通用的建议。如果您使用的是存根(例如我使用的 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
  •  0
  •   JOG    13 年前

    我的问题是打字错误。我写过 android.id (点)代替 android:id . :P

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

        13
  •  0
  •   Krzysztof Madejski    13 年前

    我也有同样的问题。

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

    我是这样解决的:

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

    如果孩子们的顺序是相反的,这也会起作用,但我想通常应该像上面那样做。

        14
  •  0
  •   Santosh    13 年前

    这个 findViewById() 方法有时返回 null 当布局的根没有 android:id android:id 根元素的属性。

        15
  •  0
  •   Mike6679    13 年前

    在我的例子中,视图在父视图中,而不是在我试图调用它的视图中。因此,在child视图中,我不得不调用:

    RelativeLayout relLayout = (RelativeLayout) this.getParent();
    View view1 = relLayout.findViewById(R.id.id_relative_layout_search);
    
        16
  •  0
  •   diter    12 年前

    “干净”的选择对我很有效。

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

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

        17
  •  0
  •   blub    11 年前

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

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

        18
  •  0
  •   Shanij P.S    10 年前

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