指定的 child 已经有一个 parent。您必须先在 child 的 parent (Android) 上调用 removeView()

The specified child already has a parent. You must call removeView() on the child's parent first (Android)

我必须经常在两种布局之间切换。错误发生在下面发布的布局中。

第一次调用我的布局时,没有发生任何错误,一切正常。当我调用另一个布局(一个空白布局)然后第二次调用我的布局时,它会抛出以下错误:

> FATAL EXCEPTION: main
>     java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

我的 layout-code 看起来像这样:

    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);
        }
    }
}

我知道以前有人问过这个问题,但对我没有帮助。

错误消息说明了您应该做什么。

// TEXTVIEW
if(tv.getParent() != null) {
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
layout.addView(tv); //  <==========  ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT

我来这里是为了用我的 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));

我找到了另一个修复方法:

if (mView.getParent() == null) {
                    myDialog = new Dialog(MainActivity.this);
                    myDialog.setContentView(mView);
                    createAlgorithmDialog();
                } else {
                    createAlgorithmDialog();
                }

这里我只有一个 if 语句检查视图是否有父视图,如果没有创建新对话框,设置 contentView 并在我的 "createAlgorithmDialog()" 方法中显示对话框。

这还会使用 onClickListeners 设置正负按钮(确定和取消按钮)。

在我的例子中,问题是由于我使用 <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()有助于解决问题。

简单传递参数

attachtoroot = false

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);

您可以使用此方法检查视图是否有子视图。

public static boolean hasChildren(ViewGroup viewGroup) {
    return viewGroup.getChildCount() > 0;
 }

如果其他解决方案不起作用,例如:

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);

检查您从片段的 onCreateView 中 return 是什么,它是单一视图还是视图组?在我的例子中,我在片段 xml 的根目录上有 viewpager,我正在 returning viewpager,当我在布局中添加视图组时,我没有更新我现在必须 return 视图组,而不是 viewpager (视图).

我收到了此消息,同时尝试使用附加到根的片段提交为 true 而不是 false,如下所示:

return inflater.inflate(R.layout.fragment_profile, container, true)

完成后:

return inflater.inflate(R.layout.fragment_profile, container, false)

成功了。

检查您是否已经添加了视图

if (textView.getParent() == null)
    layout.addView(textView);

下面的代码帮我解决了这个问题:

@Override
public void onDestroyView() {
    if (getView() != null) {
        ViewGroup parent = (ViewGroup) getView().getParent();
        parent.removeAllViews();
    }
    super.onDestroyView();
}

注意:错误来自我的片段 class,通过像这样覆盖 onDestroy 方法,我可以解决它。

frameLayout.addView(bannerAdView); <----- 如果您在此行遇到错误,请执行以下操作..

if (bannerAdView.getParent() != null)

  ((ViewGroup) bannerAdView.getParent()).removeView(bannerAdView);

   frameLayout.addView(bannerAdView);     <------ now added view
if(tv!= null){
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}

我的情况不同,子视图已经有一个父视图,我正在将父视图内的子视图添加到不同的父视图。下面的示例代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/lineGap"
>
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    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_width="wrap_content"
   android:layout_height="wrap_content"
   android:gravity="center"
   android:textColor="@color/black1" />

我的错误是这样定义视图:

view = inflater.inflate(R.layout.qr_fragment, container);

它丢失了:

view = inflater.inflate(R.layout.qr_fragment, container, false);

在我的例子中,当我想将父视图添加到其他视图时会发生这种情况

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);

您必须先从父视图中删除子视图。

如果您的项目是在 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)
}

如果此视图为空、父视图为空或父视图不是 ViewGroup,它不会安全地执行任何操作

我的问题与许多其他答案有关,但需要进行更改的原因略有不同...我试图将 Activity 转换为片段。所以我将 inflate 代码从 onCreate 移到了 onCreateView,但是我忘记了从 setContentView 转换到 inflate 方法,同样的 IllegalStateException 把我带到了这个页面。

我改变了这个:

binding = DataBindingUtil.setContentView(requireActivity(), R.layout.my_fragment)

对此:

binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false)

问题解决了。

当我为 Activity 和 Fragments 使用数据绑定时,它发生在我身上。

对于片段 - 在 onCreateView 中,我们可以使用 inflater 以传统方式扩充布局。 在 onViewCreated 方法中,绑定对象可以更新为

 binding = DataBindingUtil.getBinding<FragmentReceiverBinding>(view) as FragmentReceiverBinding

它解决了我的问题

就我而言,我这样做(错误):

...
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);
...

如果在您的 XML 中您有 ID 为“root”的布局 这是问题,只需更改 ID 名称

我遇到了同样的错误,看看我在做什么。糟糕,我试图将相同的视图 NativeAdView 添加到多个 FrameLayouts,通过为每个 FrameLayout 创建一个单独的视图 NativeAdView 来解决,谢谢

在我的例子中,我不小心 return 从 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
}

解决方案是 return 父视图 (v) 而不是子视图 (rv)。

KOTLIN 中的简化

 viewToRemove?.apply {
            if (parent != null) {
                (parent as ViewGroup).removeView(this)
            }
        }

在我的例子中,我有一个与 recyclerView 一起工作的适配器,传递给适配器的项目是具有自己视图的项目。

只需要一个 LinearLayout 来充当传递的每个项目的容器,所以我所做的是在 onBindViewHolder 内的指定位置抓取项目,然后将其添加到 LinearLayout,这然后显示。

检查 docs

中的基础知识

When an item scrolls off the screen, RecyclerView doesn't destroy its view

因此,对于我的项目,当我向一个方向滚动时,然后向相反的方向改变 - 快速,快速显示的项目没有被销毁,这意味着,项目仍然与 LinearLayout 容器相关联,然后最后,我正在尝试附加到另一个容器,该容器以 child 已经具有 parent 结束。

我的解决方案是检查指定的项目是否有 parent,如果有,我将其分配给一个变量,然后调用 parentVar.removeView(item),然后分配新的 parent .

这是示例代码(有问题的适配器):

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_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:orientation="vertical"
    android:padding="10dp" />

所以,questionWidget 似乎在可见度之外保留了 parent 将近 4 步,当我快速滚动到相反的方向时,我会遇到它仍然带有 parent,然后我尝试将它添加到另一个容器。

这是解决方法 - 选项 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)
       }
            
    
        }

实际上,在将 parent 添加到 parent 之前询问 child 是否有 parent 很重要。

你只需要传递 attachToRoot 参数 false。

mBinding = FragmentCategoryBinding.inflate(inflater, container, false)

我尝试了你们建议的所有方法,但没有成功。

但是,我设法通过将所有绑定初始化从 onCreate 移动到 onCreateView[=22 来修复它=].

onCreate(){
        binding = ScreenTicketsBinding.inflate(layoutInflater)
}

移动到

onCreateView(...){
            binding = ScreenTicketsBinding.inflate(layoutInflater) 
}

在我的例子中,我将 id 命名为“root”用于约束布局,这与现有的父根 id 冲突。

尝试更改id。

<androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/root"  //<--It should not named as root.
            android:layout_width="match_parent"
            android:layout_height="match_parent"

</androidx.constraintlayout.widget.ConstraintLayout>

如果您使用的是 ViewBinding,请确保您指的是正确的绑定!

我在尝试从 activity:

中扩展自定义对话框时遇到了这个问题
AlertDialog.Builder builder = new AlertDialog.Builder(this);

final AlertBinding alertBinding = AlertBinding.inflate(LayoutInflater.from(this), null, false);

builder.setView(binding.getRoot()); // <--- I was using binding (which is my Activity's binding), instead of alertBinding.

这是我自定义对话框的方式

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
android.view.View views = getLayoutInflater().inflate(layout_file, null, false);

builder.setView(views);
dialog = builder.create();
dialog.show();

我把它改成了这个,对我有用,希望对你有帮助

Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(layout_file);
dialog.show();