指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView() (Android)
Posted
技术标签:
【中文标题】指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView() (Android)【英文标题】:The specified child already has a parent. You must call removeView() on the child's parent first (Android) 【发布时间】:2015-03-20 05:11:28 【问题描述】:我必须经常在两种布局之间切换。错误发生在下面发布的布局中。
当我的布局第一次被调用时,没有发生任何错误,一切都很好。然后当我调用不同的布局(空白的)然后再次调用我的布局时,它会引发以下错误:
> FATAL EXCEPTION: main
> java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
我的布局代码如下所示:
tv = new TextView(getApplicationContext()); // are initialized somewhere else
et = new EditText(getApplicationContext()); // in the code
private void ConsoleWindow()
runOnUiThread(new Runnable()
@Override
public void run()
// MY LAYOUT:
setContentView(R.layout.activity_console);
// LINEAR LAYOUT
LinearLayout layout=new LinearLayout(getApplicationContext());
layout.setOrientation(LinearLayout.VERTICAL);
setContentView(layout);
// TEXTVIEW
layout.addView(tv); // <========== ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT
et.setHint("Enter Command");
layout.addView(et);
我知道以前有人问过这个问题,但对我的情况没有帮助。
【问题讨论】:
只为遇到同样错误的人:确保添加正确的元素。假设您必须添加LinearLayout
,但您添加TextView
。所以修复它。
当使用 android 数据绑定时不应该用 id 'root' 声明视图,它会导致同样的错误。
使用TranstitionManager.beginDelayedTransition
的朋友请查看我的answer here
【参考方案1】:
错误消息说明了您应该做什么。
// TEXTVIEW
if(tv.getParent() != null)
((ViewGroup)tv.getParent()).removeView(tv); // <- fix
layout.addView(tv); // <========== ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT
【讨论】:
【参考方案2】:只需传递参数
attachtoroot = 假
View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
【讨论】:
对我来说,这是一个靶心。 recycleView 中项目的约束布局,基于运行时动态更改约束。 ConstraintSet.apply 没有工作,直到这个。因此,在 onCreateViewHolder 中传播父级,但将 false 作为附加参数发送到 inflating。 这是正确的解决方案!正如@Sniper 所说,将 null 传递给第二个参数可能会导致子视图无法与其父视图对齐。 OTOH 传递父级可能会导致有问题的错误。所以,attachToRoot
= false,才是正确的选择。【参考方案3】:
我来到这里是为了用我的 recyclerview 搜索错误,但解决方案不起作用(显然)。我已经写了recyclerview的原因和解决方案。希望它可以帮助某人。
如果在onCreateViewHolder()
中遵循以下方法会导致错误:
layoutInflater = LayoutInflater.from(context);
return new VH(layoutInflater.inflate(R.layout.single_row, parent));
应该是
return new VH(layoutInflater.inflate(R.layout.single_row, null));
【讨论】:
有时随机答案并不完全是对所问问题的答案,这对其他人有所帮助。这对我有用。谢谢! 很好!这就是为什么人们应该在大多数时候将“null”作为二维参数传递给inflaters。谢谢。 将 Null 传递给负责父级的参数是一个不错的主意,但您必须知道,在这种情况下,子视图(您膨胀的那个)将无法正确测量它自己在某些情况下,因为它对父母一无所知。在某些情况下它会起作用,但在某些情况下不会。 请注意,这可能会导致无法正确解析 viewholders 主题。【参考方案4】:我在尝试使用附加到 root 将片段提交为 true 而不是 false 时收到 此消息,如下所示:
return inflater.inflate(R.layout.fragment_profile, container, true)
做完之后:
return inflater.inflate(R.layout.fragment_profile, container, false)
成功了。
【讨论】:
【参考方案5】:frameLayout.addView(bannerAdView);
if (bannerAdView.getParent() != null)
((ViewGroup) bannerAdView.getParent()).removeView(bannerAdView);
frameLayout.addView(bannerAdView); <------ now added view
【讨论】:
【参考方案6】:如果其他解决方案不起作用:
View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
检查您从片段的 onCreateView 返回的内容是单个视图还是视图组?在我的情况下,我在片段的 xml 的根目录上有 viewpager,我正在返回 viewpager,当我在布局中添加 viewgroup 时,我没有更新我现在必须返回 viewgroup,而不是 viewpager(view)。
【讨论】:
【参考方案7】:我的错误是这样定义视图:
view = inflater.inflate(R.layout.qr_fragment, container);
它不见了:
view = inflater.inflate(R.layout.qr_fragment, container, false);
【讨论】:
【参考方案8】:在我的情况下,当我想将父视图添加到其他视图时会发生这种情况
View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(lyt); // -> crash
你必须像这样添加父视图
View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(root);
【讨论】:
非常感谢@Maysam。你节省了我的时间【参考方案9】:在 KOTLIN 中简化
viewToRemove?.apply
if (parent != null)
(parent as ViewGroup).removeView(this)
【讨论】:
【参考方案10】:您必须先将子视图从其父视图中移除。
如果您的项目使用 Kotlin,您的解决方案看起来会与 Java 略有不同。 Kotlin 使用 as?
简化了转换,如果左侧为 null 或转换失败,则返回 null。
(childView.parent as? ViewGroup)?.removeView(childView)
newParent.addView(childView)
Kotlin 扩展解决方案
如果您需要多次执行此操作,请添加此扩展以使您的代码更具可读性。
childView.removeSelf()
fun View?.removeSelf()
this ?: return
val parentView = parent as? ViewGroup ?: return
parentView.removeView(this)
如果此 View 为 null、父视图为 null 或父视图不是 ViewGroup,它不会安全地执行任何操作
【讨论】:
【参考方案11】:在我的情况下,问题是由于我使用 <merge>
布局膨胀父视图这一事实引起的。在这种情况下,addView()
导致了崩溃。
View to_add = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, true);
// parent_layout.addView(to_add); // THIS CAUSED THE CRASH
删除 addView()
有助于解决问题。
【讨论】:
【参考方案12】:下面的代码为我解决了这个问题:
@Override
public void onDestroyView()
if (getView() != null)
ViewGroup parent = (ViewGroup) getView().getParent();
parent.removeAllViews();
super.onDestroyView();
注意:错误来自我的片段类,通过像这样覆盖 onDestroy 方法,我可以解决它。
【讨论】:
【参考方案13】:检查您是否已经添加了视图
if (textView.getParent() == null)
layout.addView(textView);
【讨论】:
【参考方案14】:if(tv!= null)
((ViewGroup)tv.getParent()).removeView(tv); // <- fix
【讨论】:
【参考方案15】:在我的情况下,我不小心从 Layout.onCreateView() 中返回了一个子视图,如下所示:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View v= inflater.inflate(R.layout.activity_deliveries, container, false);
RecyclerView rv = (RecyclerView) v.findViewById(R.id.deliver_list);
return rv; // <- here's the issue
解决方案是返回父视图 (v) 而不是子视图 (rv)。
【讨论】:
【参考方案16】:你只需要传递attachToRoot参数false。
mBinding = FragmentCategoryBinding.inflate(inflater, container, false)
【讨论】:
【参考方案17】:在我的例子中,我将约束布局的 id 命名为“root”,这与现有的父根 id 冲突。
尝试更改 id。
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/root" //<--It should not named as root.
android:layout_
android:layout_
</androidx.constraintlayout.widget.ConstraintLayout>
【讨论】:
【参考方案18】:我找到了另一个解决方法:
if (mView.getParent() == null)
myDialog = new Dialog(MainActivity.this);
myDialog.setContentView(mView);
createAlgorithmDialog();
else
createAlgorithmDialog();
这里我只有一个 if 语句检查视图是否有父视图,如果它没有创建新对话框,设置 contentView 并在我的“createAlgorithmDialog()”方法中显示对话框。
这也使用 onClickListeners 设置肯定和否定按钮(确定和取消按钮)。
【讨论】:
【参考方案19】:我的问题与许多其他答案有关,但需要进行更改的原因略有不同...我试图将 Activity 转换为 Fragment。所以我把inflate代码从onCreate移到onCreateView,但是忘了从setContentView转换到inflate方法,同样的IllegalStateException把我带到了这个页面。
我改变了这个:
binding = DataBindingUtil.setContentView(requireActivity(), R.layout.my_fragment)
到这里:
binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false)
这解决了问题。
【讨论】:
【参考方案20】:就我而言,我有一个与 recyclerView 配合使用的适配器,传递给适配器的项目是具有自己视图的项目。
所需的只是一个 LinearLayout 来充当每个传递的项目的容器,所以我所做的是在 onBindViewHolder
内的指定位置抓取项目,然后将其添加到 LinearLayout,然后显示。
检查docs中的基础知识,
当一个项目滚出屏幕时,RecyclerView 不会销毁它 查看
因此,对于我的项目,当我向一个方向滚动时,然后向相反的方向改变 - 快速,快速显示的项目没有被破坏,这意味着项目仍然与 LinearLayout 容器相关联,然后在我结束,我正在尝试附加到另一个容器,结果是孩子已经有了父母。
我的解决方案是检查指定项是否有父项,如果有,我将其分配给一个变量,然后调用parentVar.removeView(item)
,然后分配新的父项。
这是示例代码(有问题的适配器):
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int)
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
holder.linearLayoutContainer.addView(questionWidget)/*addView throws error once in a while*/
inner class QuestionWidgetViewHolder(mView: View) :
RecyclerView.ViewHolder(mView)
val linearLayoutContainer: LinearLayout =
mView.findViewById(R.id.custom_question_widget_container)
R.id.custom_question_widget_container 的内容:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_question_widget_container"
android:layout_
android:layout_
android:layout_margin="10dp"
android:orientation="vertical"
android:padding="10dp" />
所以,questionWidget
似乎在可见性之外将父级保留了近 4 步,当我快速滚动到相反的方向时,我仍然会遇到它的父级,然后我正在尝试添加它到另一个容器。
这是解决方法 - 选项 1:
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int)
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
val initialWidgetParent : ViewParent? = questionWidget.parent
//attempt to detach from previous parent if it actually has one
(initialWidgetParent as? ViewGroup)?.removeView(questionWidget)
holder.linearLayoutContainer.addView(questionWidget)
另一个更好的解决方案 - 选项 2:
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int)
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
val initialWidgetParent : ViewParent? = questionWidget.parent
//if it's in a parent container already, just ignore adding it to a view, it's already visible
if(initialWidgetParent == null)
holder.linearLayoutContainer.addView(questionWidget)
实际上,在将孩子添加到父母之前,需要询问孩子是否有父母。
【讨论】:
【参考方案21】:我尝试了你们建议的所有方法,但没有成功。
但是,我设法通过将所有绑定初始化从 onCreate 移动到 onCreateView 来修复它。
onCreate()
binding = ScreenTicketsBinding.inflate(layoutInflater)
移至
onCreateView(...)
binding = ScreenTicketsBinding.inflate(layoutInflater)
【讨论】:
【参考方案22】:您可以使用此方法检查视图是否有子视图。
public static boolean hasChildren(ViewGroup viewGroup)
return viewGroup.getChildCount() > 0;
【讨论】:
【参考方案23】:我的情况不同,子视图已经有一个父视图,我将父视图中的子视图添加到不同的父视图。下面的示例代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_
android:layout_
android:layout_margin="@dimen/lineGap"
>
<TextView
android:layout_
android:layout_
android:textColor="@color/black1"
android:layout_gravity="center"
android:gravity="center"
/>
</LinearLayout>
我正在膨胀这个视图并添加到另一个 LinearLayout,然后我从上面的布局中删除了 LinaarLayout 并开始工作
下面的代码解决了这个问题:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:gravity="center"
android:textColor="@color/black1" />
【讨论】:
【参考方案24】:当我对 Activity 和 Fragments 使用 Databinding 时发生了这种情况。
对于片段 - 在 onCreateView 中,我们可以使用充气器以传统方式充气布局。 在 onViewCreated 方法中,绑定对象可以更新为
binding = DataBindingUtil.getBinding<FragmentReceiverBinding>(view) as FragmentReceiverBinding
解决了我的问题
【讨论】:
【参考方案25】:就我而言,我这样做(错误):
...
TextView content = new TextView(context);
for (Quote quote : favQuotes)
content.setText(quote.content);
...
而不是(好):
...
for (Quote quote : favQuotes)
TextView content = new TextView(context);
content.setText(quote.content);
...
【讨论】:
【参考方案26】:如果在你的 XML 中有 id 为 "root" 的布局,那就是问题,只需更改 id 名称
【讨论】:
【参考方案27】:我遇到了同样的错误,看看我在做什么。我的错,我试图将相同的视图 NativeAdView
添加到多个 FrameLayouts
,通过为每个 FrameLayout
创建单独的视图 NativeAdView
来解决,谢谢
【讨论】:
以上是关于指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView() (Android)的主要内容,如果未能解决你的问题,请参考以下文章
我继续收到错误消息“指定的孩子已经有一个父母。您必须首先在该孩子的父母上调用removeView()(Android)
冲突的 Android 错误消息:指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()
指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()
Fragments - 指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()
收到错误“指定的孩子已经有父母。您必须先在孩子的父母上调用 removeView()。”? [复制]
Android - ArrayAdapter<LinearLayout> :指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()