findViewById()在布局XML中为自定义组件返回null,而不是其他组件
我有一个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"); }
其他元素被成功find,但是foo
返回null。 MyCustomView有一个构造函数MyCustomView(Context c, AttributeSet a)
和一个Log.d(...)
在构造函数的最后成功出现在logcat之前的“史诗般的失败”。
为什么foo
空?
因为在构造函数中,我super(context)
而不是super(context, attrs)
。
有意义的是,如果你不传入属性,如id,那么视图将没有id,因此不能使用该idfind。 🙂
我有同样的问题。 我的错误是:我写了
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);
我写了我的解决scheme,以防有人遇到同样的问题。
似乎有多种原因。 我只是在Eclipse中使用“Clean …”来解决类似的问题。 (FindViewByID之前工作,由于某种原因开始返回null。)
我有同样的问题,因为在我的自定义视图中,我重写了构造函数,但调用超级构造函数与attrs参数。 那是复制粘贴)
我以前的构造函数版本:
public TabsAndFilterRelativeLayout(Context context, AttributeSet attrs) { super(context); }
我现在有:
public TabsAndFilterRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs);}
那可行!
同样的问题,但不同的解决scheme:我没有打电话
setContentView(R.layout.main)
之前我试图find这里所述的观点
如果您有多个布局版本(取决于屏幕密度,SDK版本),请确保它们都包含您正在查找的元素。
在我的情况下,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" />
确保在findViewById(...)
语句之前调用setContentView(R.layout.main)
findViewById(...)
语句;
对我来说,当我将res文件夹添加到项目设置中的Java Build Path中的Source时,问题就解决了。
我遇到同样的问题,当我通过布局XML添加一个自定义视图,然后尝试附加在应用程序的其他地方callback…
我创build了一个自定义视图,并将其添加到我的“layout_main.xml”
public class MUIComponent extends SurfaceView implements SurfaceHolder.Callback { public MUIComponent (Context context, AttributeSet attrs ) { super ( context, attrs ); } // .. }
在主Activity中,我想附加一些callback,并从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膨胀布局,并使用膨胀的布局来进行查找
这发生在我身上的是Wear的一个自定义组件,但是这是一个通用的build议。 如果你使用的是存根(比如我使用的是WatchViewStub
),那么你不能只把调用放到findViewById()
任何地方。 存根(stub)内的所有东西都必须首先被膨胀,这不仅发生在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); ...
我的问题是一个错字。 我写了android.id
(点),而不是android:id
。 :P
显然,在我的自定义组件xml中没有语法检查。 🙁
有同样的问题。
我有几个孩子的布局。 从一个他们的构造函数,我试图获得引用(通过使用context.findViewById)给其他孩子。 这是不行的,因为第二个孩子是在布局进一步定义。
我已经解决了这个问题:
setContentView(R.layout.main); MyView first = findViewById(R.layout.first_child); first.setSecondView(findViewById(R.layout.second_child));
如果孩子们的顺序是相反的,那也是一样,但是我想一般应该像上面这样做。
当layout的根没有android:id
属性时, findViewById()
方法有时会返回null
。 用于生成布局xml文件的Eclipse向导不会自动为根元素生成android:id
属性。
在我的情况下,视图是在父母不是在我试图调用它的视图。所以在子视图中,我不得不打电话:
RelativeLayout relLayout = (RelativeLayout) this.getParent(); View view1 = relLayout.findViewById(R.id.id_relative_layout_search);
“干净”选项为我工作。
在我的情况下,根本原因是源代码驻留在networking共享,我的工作站和文件服务器没有正确同步,并已漂移了5秒。 由Eclipse创build的文件的时间戳过去(因为它们由文件服务器分配)与工作站的时钟相关,导致Eclipse错误地parsing生成的文件和源文件之间的依赖关系。 在这种情况下,一个“干净的”似乎工作,因为它强制一个完整的重build,而不是依赖于错误的时间戳的增量构build。
一旦我在我的工作站上修复了NTP设置,问题再也没有发生过。 如果没有正确的NTP设置,每隔几个小时就会发生一次,因为时钟漂移很快。
要添加另一个微不足道的错误的答案要留意:
检查你是否正在编辑正确的布局XML文件…
我有同样的问题,因为我忘了更新所有我的布局文件夹中的视图ID。