У указанного ребенка уже есть родитель. Сначала вы должны вызвать removeView () у родителя ребенка (Android)


164

Мне приходится часто переключаться между двумя раскладками. Ошибка происходит в макете, размещенном ниже.

Когда мой макет вызывается в первый раз, ошибки не возникает, и все в порядке. Когда я затем вызываю другой макет (пустой) и затем вызываю мой макет во второй раз, он выдает следующую ошибку:

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

Я знаю, что этот вопрос уже задавался, но в моем случае это не помогло.


1
Просто для тех, кто получает ту же ошибку: убедитесь, что вы добавили правильный элемент. Допустим, вы должны добавить, LinearLayoutно вы добавляете TextView. Так что исправь это.
Разработчик

при использовании привязки данных Android не следует объявлять представление с идентификатором 'root', это вызывает ту же ошибку.
Мохаммад Реза Хахани

для тех TranstitionManager.beginDelayedTransition, кто использует , пожалуйста, проверьте мой ответ здесь
mochadwi

Ответы:


354

Сообщение об ошибке говорит, что вы должны сделать.

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

58

просто передайте аргумент attachtoroot как ложный

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

2
Для меня это был яблочко. Макет ограничения для элементов в recycleView, динамическое изменение ограничений в зависимости от времени выполнения. ConstraintSet.apply не работал, до этого. Итак, распространяйте parent в onCreateViewHolder, но отправляйте false как дополнительный параметр для надувания.
Miroslavign

3
Это правильное решение! Как сказал @Sniper, передача нулевого значения второму параметру может привести к тому, что дочернее представление не будет выровнено, как это должно быть с его родителем. OTOH передача родителя может вызвать ошибку, о которой идет речь. Итак, attachToRoot= ложь, это путь.
Вассилис

Правильный способ сделать это.
Роуланд Мтетези

Это должно быть принято в качестве ответа.
Михаил

50

Я пришел сюда при поиске ошибки с моимайзером, но решение не сработало (очевидно). Я написал причину и решение для нее на случай повторного просмотра. Надеюсь, это кому-нибудь поможет.

Ошибка вызывается, если 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));

15
Иногда случайные ответы, которые не совсем являются ответами на заданные вопросы, помогают кому-то еще. Это сработало для меня. Спасибо!
Аджит Мемана

1
Приятно !, и именно поэтому люди в большинстве случаев должны передавать «ноль» как 2d параметры в инфляторах. Спасибо.
superUser

4
Передача Null параметру, отвечающему за родителя, не является плохой идеей, но вы должны знать, что в этом случае дочернее представление (то, которое вы надуваете) не сможет измерить себя самостоятельно в некоторых случаях, потому что оно не знать что-нибудь о родителе. В некоторых случаях это будет работать, но в некоторых - нет.
Стойчо Андреев

1
Обратите внимание, что это может привести к неправильному разрешению темы виджетов.
SpaceBison

13

Я получил это сообщение , пытаясь зафиксировать фрагмент, используя присоединение к корню в true вместо false, вот так:

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

После выполнения:

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

Это сработало.


5

Если другое решение не работает, как:

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

проверить, что вы возвращаете из onCreateView фрагмента, это один вид или группа просмотра? в моем случае у меня был viewpager в корне xml фрагмента, и я возвращал viewpager, когда я добавил viewgroup в макет, я не обновил, что я должен возвращать viewgroup сейчас, а не viewpager (view).


5

frameLayout.addView (bannerAdView); <----- если вы получили ошибку в этой строке, сделайте, как показано ниже ..

if (bannerAdView.getParent() != null)

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

   frameLayout.addView(bannerAdView);     <------ now added view

4

Моя ошибка была определить вид следующим образом:

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

Не хватало

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

3

В моем случае проблема была вызвана тем, что я раздувал родительский вид с <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()помогло решить проблему.



2

Код ниже решил это для меня:

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

Примечание: ошибка была из моего класса фрагмента, и, переопределив метод onDestroy следующим образом, я мог бы ее исправить.



2

В моем случае это происходит, когда я хочу добавить представление по родителю в другое представление

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

2

Сначала вы должны удалить дочернее представление от его родителя.

Если ваш проект находится в Kotlin, ваше решение будет выглядеть немного иначе, чем Java. Kotlin упрощает приведение as?, возвращая ноль, если левая сторона равна нулю или произойдет сбой.

(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


1

Я нашел другое исправление:

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

Здесь у меня просто есть оператор if, проверяющий, есть ли у представления родительский элемент, и если он не создал новый диалог, установите contentView и отобразите диалог в моем методе «createAlgorithmDialog ()».

Это также устанавливает положительные и отрицательные кнопки (кнопки «ОК» и «Отмена») с помощью onClickListeners.


0

Вы можете использовать этот метод, чтобы проверить, есть ли у представления дети или нет.

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

0

Мой случай был другим, дочернее представление уже имело родительское представление, я добавляю дочернее представление в родительском представлении другому родителю. пример кода ниже

<?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" />

0

Моя проблема связана со многими другими ответами, но немного другой причиной необходимости внесения изменений ... Я пытался преобразовать действие в фрагмент. Поэтому я переместил код накачки из onCreate в onCreateView, но я забыл преобразовать setContentView в метод inflate, и то же исключение IllegalStateException привело меня на эту страницу.

Я изменил это:

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

к этому:

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

Это решило проблему.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.