【问题标题】:The specified child already has a parent. You must call removeView() on the child's parent first (Android)指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView() (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

标签: java android android-edittext textview parent-child


【解决方案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】:

                在我的情况下,问题是由于我使用 &lt;merge&gt; 布局膨胀父视图这一事实引起的。在这种情况下,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_width="match_parent"
                                        android:layout_height="match_parent"
                            
                            </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_width="match_parent"
                                      android:layout_height="wrap_content"
                                      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_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" />
                                        

                                        【讨论】:

                                          【解决方案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 来解决,谢谢

                                                【讨论】:

                                                  猜你喜欢
                                                  • 2015-09-06
                                                  • 1970-01-01
                                                  • 1970-01-01
                                                  • 1970-01-01
                                                  • 1970-01-01
                                                  • 2013-10-18
                                                  相关资源
                                                  最近更新 更多