冲突的 Android 错误消息:指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()
Posted
技术标签:
【中文标题】冲突的 Android 错误消息:指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()【英文标题】:Conflicting Android error messages: The specified child already has a parent. You must call removeView() on the child's parent first 【发布时间】:2014-03-05 16:58:09 【问题描述】:最初我得到了这个错误:
指定的孩子已经有一个父母。您必须调用 removeView() 首先是孩子的父母
在
customSection.addView(customLayout);
所以我加了
((LinearLayout)customLayout.getParent()).removeView(customLayout);
现在得到
java.lang.NullPointerException
那么如果孩子有父母,我必须先将孩子从父母中移除,为什么getParent()返回null?
我有一个抽象片段,它允许派生类为列表适配器提供自定义布局。相关代码:
绑定:
public void bind(DataObject row)
View customLayout = getChildItemView(row);
if (customLayout != null)
((LinearLayout) customLayout.getParent()).removeView(customLayout);
customSection.removeAllViews();
customSection.addView(customLayout);
customSection.setVisibility(View.VISIBLE);
else
customLayout.setVisibility(View.INVISIBLE);
protected View getChildItemView(CommonRow row)
if (parentView == null)
parentView = (LinearLayout) LayoutInflater.from(getActivity())
.inflate(R.layout.list_item_custom_section,
new LinearLayout(getActivity()), true);
label = (TextView) parentView.findViewById(R.id.txtData1Label);
value = (TextView) parentView.findViewById(R.id.txtData1Value);
label.setText("Minimum");
value.setText(manager.formatMoney(((SpecificDataRow) row).minimum));
return parentView;
我也试过inflater.inflate(R.layout.list_item_custom_section, null)
... false,null / false,什么给出?
编辑:
@allprog,我知道需要进行一些清理。我在一天结束时有点匆忙地写了这个。我已经清理了代码,并分离了视图的绑定和膨胀。清理代码:
private class ViewHolder
....
public ViewHolder(View v)
Butterknife.inject(this, v);
View custom = createCustomView(customSection);
if (custom != null)
customSection.setVisibility(View.VISIBLE);
customSection.addView(custom);
public void bind(CommonRow row)
......
bindCustomView(row, customSection);
儿童班:
@Override
protected View createCustomView(ViewGroup parent)
return LayoutInflater.from(getActivity()).inflate(R.layout.list_item_custom_section, parent, false);
@Override
protected void bindCustomView(CommonRow row, ViewGroup section)
TextView label = Views.findById(section, R.id.txtData1Label);
TextView value = Views.findById(section, R.id.txtData1Value);
label.setText("Minimum");
value.setText(manager.formatMoney(((SpecificRow) row).minimum));
suitianshi 首先得到了它,我原来的 [unkempt] 代码就是解决方案。
【问题讨论】:
什么是customSection
?你能展示一下第一次初始化的代码吗?
它在 getChildItemView(CommonRow row) 方法中。 parentView = (LinearLayout)LayoutInflater.from(getActivity()).inflate(R.layout.list_item_custom_section, new LinearLayout(getActivity()), true);
您可以发布 list_item_custom_section 的 XML 吗?我怀疑您正在尝试将视图添加到自身。加上变量customSection
仍然需要在某处声明(和设置)。你能发布那个代码吗?
缺少一些东西 - 正如@JStevenPerry 所问的那样,customSection
初始化不存在。您回答的是customLayout
充气机。我们需要看看customSection
是如何定义的以及它到底是什么。
尝试清理你的代码。正如@Dmide 指出的那样,您使用一个字段作为 parentView。这是一个坏主意。此外,getChildItemView
尽管它的名字实际上有副作用。我想,如果你清理了这个混乱,一切都会开始正常运行。 (PS:调试器是你的朋友!)
【参考方案1】:
试试这个:
public void bind(DataObject row)
View customLayout = getChildItemView(row);
if (customLayout != null)
if(customLayout.getParent() != null)
((LinearLayout)customLayout.getParent()).removeView(customLayout);
customSection.removeAllViews();
customSection.addView(customLayout);
customSection.setVisibility(View.VISIBLE);
else
customLayout.setVisibility(View.INVISIBLE);
我已经阅读了相关的源代码,当view
有父级时,getParent
应该返回非空值。在转换和调用 removeView
希望这会有所帮助。
源代码:
在View
:
public final ViewParent getParent()
return mParent;
在ViewGroup.addViewInner
if (child.getParent() != null)
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
【讨论】:
我理解那部分,问题是 customSection.addView(customLayout) 失败并出现 OP 标题中的错误。因此,我可以整天检查 null ,但它仍然无法帮助我从其原始 [显然为 null] 父级中删除 customLayout。对我来说没有意义。 在我的回答中添加了源代码。你的意思是你得到了那个例外,但getParent
reuturns null?这真的很奇怪!
您是否尝试将ViewParent
转换为ViewGroup
而不是LinearLayout
?
ViewGroup 中的所有 addView 方法最终都会经过addViewInner()
。这就是 IllegalStateException 的来源。如果 getParent()
返回 null,则它永远不会被抛出。你确定你不会不小心多次将相同的视图添加到同一个父级吗? android.googlesource.com/platform/frameworks/base/+/refs/heads/…【参考方案2】:
我可以看到您的parentView
是一个字段变量,这是关键。所以我怀疑是真的发生了什么:
bind()
的第一次调用:您创建 parentView
并且它还没有父级,customSection.addView(customLayout);
工作正常,但是在您添加对父级的检查后,它在此处失败。
bind()
的第二次调用:parentView
现在有一个父级,您添加的检查现在应该可以工作,但是您在上一步中失败了。如果没有检查,您将在此处失败,但标题异常。
解决方案:检查父级是否存在并仅在必要时将其删除。
【讨论】:
【参考方案3】:首先,LayoutInflater inflate 方法总是返回没有父视图的视图。
如果attachToRoot == true
parentView
将是new LinearLayout(getActivity())
如果attachToRoot == false
parentView
将被夸大R.layout.list_item_custom_section
不管它是什么。
在两种情况下,((LinearLayout) customLayout.getParent())
将为空。这就是您收到NullPointerException
的原因。你可以在LayoutInflater documentation的return语句中看到它。
如上所述,将parentView
声明为字段是bad aproach,它应该是方法参数,如果== null(来自AdapterView 的方法),您将膨胀。
顺便说一句:如果调用代码中的第 9 行,它将抛出 NullPointerException
,因为它仅在 customLayout == null
的情况下被调用!!!
【讨论】:
以上是关于冲突的 Android 错误消息:指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()的主要内容,如果未能解决你的问题,请参考以下文章
指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView() (Android)
Android - ArrayAdapter<LinearLayout> :指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()
收到错误“指定的孩子已经有父母。您必须先在孩子的父母上调用 removeView()。”? [复制]
IllegalStateException,指定的孩子已经有一个父母 - ListFragment