findViewById() 为布局 XML 中的自定义组件返回 null,而不是其他组件
Posted
技术标签:
【中文标题】findViewById() 为布局 XML 中的自定义组件返回 null,而不是其他组件【英文标题】:findViewById() returns null for custom component in layout XML, not for other components 【发布时间】: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
为空?
【问题讨论】:
【参考方案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_
android:layout_
/>
我发现当我添加 xmlns 的东西时,它的工作原理是这样的:
<com.gerfmarquez.seekbar.VerticalSeekBar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/verticalSeekBar"
android:layout_
android:layout_
/>
【讨论】:
【参考方案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。
【讨论】:
以上是关于findViewById() 为布局 XML 中的自定义组件返回 null,而不是其他组件的主要内容,如果未能解决你的问题,请参考以下文章
findViewById() 为对话框中的视图返回 null