Anak yang ditentukan sudah memiliki orangtua. Anda harus memanggil removeView () pada orang tua anak terlebih dahulu (Android)

164

Saya harus sering beralih di antara dua tata letak. Kesalahan terjadi pada tata letak yang diposting di bawah ini.

Ketika tata letak saya disebut pertama kali, tidak ada kesalahan dan semuanya baik-baik saja. Ketika saya kemudian memanggil tata letak yang berbeda (yang kosong) dan kemudian memanggil tata letak saya untuk kedua kalinya, itu melempar kesalahan berikut:

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

Lay-code saya terlihat seperti ini:

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

Saya tahu pertanyaan ini telah diajukan sebelumnya, tetapi itu tidak membantu dalam kasus saya.

blackst0ne
sumber
1
Hanya untuk seseorang yang mendapat kesalahan yang sama: Pastikan Anda menambahkan elemen yang benar. Katakanlah Anda harus menambahkan LinearLayouttetapi Anda menambahkan TextView. Jadi perbaiki.
Pengembang
saat menggunakan penyatuan data android seharusnya tidak menyatakan tampilan dengan id 'root', itu menyebabkan kesalahan yang sama.
Mohammad Reza Khahani
bagi yang menggunakan TranstitionManager.beginDelayedTransition, silakan periksa jawaban
mochadwi

Jawaban:

354

Pesan kesalahan mengatakan apa yang harus Anda lakukan.

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

cukup berikan argumen attachtoroot sebagai false

View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
Studi Pb
sumber
2
Bagi saya, ini adalah bullseye. Batasi tata letak untuk item dalam recycleView, yang secara dinamis mengubah batasan berdasarkan runtime. ConstraintSet.apply tidak berfungsi, sampai ini. Jadi, sebarkan induk di onCreateViewHolder, tetapi kirim false sebagai parameter tambahan untuk digembungkan.
miroslavign
3
Ini solusi yang tepat! Seperti yang dikatakan @Sniper, meneruskan null ke param kedua dapat menyebabkan tampilan anak tidak menyelaraskan dirinya sebagaimana seharusnya ke induknya. OTOH melewati orang tua dapat menyebabkan kesalahan yang dimaksud. Jadi, attachToRoot= salah, adalah jalan yang harus ditempuh.
Vassilis
Cara yang benar untuk melakukannya.
Rowland Mtetezi
50

Saya datang ke sini untuk mencari kesalahan dengan recyclerview saya tetapi solusinya tidak bekerja (jelas). Saya telah menulis penyebab dan solusi untuknya dalam kasus recyclerview. Semoga ini bisa membantu seseorang.

Kesalahan ini disebabkan jika dalam onCreateViewHolder()metode berikut ini diikuti:

layoutInflater = LayoutInflater.from(context);
return new VH(layoutInflater.inflate(R.layout.single_row, parent));

Sebaliknya seharusnya

return new VH(layoutInflater.inflate(R.layout.single_row, null));
suku
sumber
15
Terkadang jawaban acak yang bukan jawaban untuk pertanyaan yang diajukan membantu orang lain. Ini berhasil untuk saya. Terima kasih!
Ajith Memana
1
Bagus !, dan itulah mengapa orang-orang harus melewati "null" sebagai parameter 2d di inflaters. Terima kasih.
super Pengguna
4
Melewati Null ke parameter yang bertanggung jawab untuk orang tua bukanlah ide yang buruk, tetapi Anda harus tahu bahwa dalam kasus ini tampilan anak (yang Anda kembang) tidak akan dapat mengukurnya sendiri dengan benar dalam beberapa kasus, karena tidak tahu apa-apa tentang orang tua. Dalam beberapa kasus itu akan berhasil tetapi dalam beberapa tidak.
Stoycho Andreev
1
Perhatikan bahwa ini dapat menyebabkan tema pemirsa tidak terselesaikan dengan benar.
SpaceBison
13

Saya mendapat pesan ini saat mencoba melakukan fragmen menggunakan attach to root to true, bukan false, seperti:

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

Setelah melakukan:

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

Itu berhasil.

Hudson Pereira
sumber
5

Jika solusi lain tidak berfungsi seperti:

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

periksa apa yang Anda kembali dari onCreateView dari fragmen apakah itu tampilan tunggal atau grup tampilan? dalam kasus saya, saya punya viewpager pada root xml of fragment dan saya kembali viewpager, ketika saya menambahkan viewgroup dalam tata letak saya tidak memperbarui bahwa saya harus mengembalikan viewgroup sekarang, bukan viewpager (tampilan).

Elang Hitam
sumber
5

frameLayout.addView (bannerAdView); <----- jika Anda mendapatkan kesalahan pada baris ini, lakukan seperti di bawah ini ..

if (bannerAdView.getParent() != null)

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

   frameLayout.addView(bannerAdView);     <------ now added view
Mayur Dabhi
sumber
4

Kesalahan saya adalah mendefinisikan tampilan seperti ini:

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

Itu hilang:

view = inflater.inflate(R.layout.qr_fragment, container, false);
Pedro Molina
sumber
3

Dalam kasus saya masalahnya disebabkan oleh fakta bahwa saya menggembungkan tampilan induk dengan <merge>tata letak. Dalam hal ini, addView()menyebabkan crash.

View to_add = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, true);
// parent_layout.addView(to_add); // THIS CAUSED THE CRASH

Menghapus addView()membantu memecahkan masalah.

soshial
sumber
2

periksa apakah Anda sudah menambahkan tampilan

if (textView.getParent() == null)
    layout.addView(textView);
Dan Alboteanu
sumber
2

Kode di bawah ini menyelesaikannya untuk saya:

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

Catatan: Kesalahan berasal dari kelas fragmen saya dan dengan mengganti metode onDestroy seperti ini, saya bisa menyelesaikannya.

AK 12
sumber
2
if(tv!= null){
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
Chandan Bera
sumber
2

Dalam kasus saya itu terjadi ketika saya ingin menambahkan tampilan oleh orang tua ke tampilan lain

View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(lyt);  // ->  crash

Anda harus menambahkan tampilan induk seperti ini

View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(root);
Maysam R
sumber
2

Anda harus terlebih dahulu menghapus tampilan anak dari induknya.

Jika proyek Anda berada di Kotlin, solusi Anda akan terlihat sedikit berbeda dari Java. Kotlin menyederhanakan casting dengan as?, mengembalikan nol jika sisi kiri adalah nol atau pemain gagal.

(childView.parent as? ViewGroup)?.removeView(childView)
newParent.addView(childView)

Solusi Ekstensi Kotlin

Jika Anda perlu melakukan ini lebih dari sekali, tambahkan ekstensi ini untuk membuat kode Anda lebih mudah dibaca.

childView.removeSelf()

fun View?.removeSelf() {
    this ?: return
    val parentView = parent as? ViewGroup ?: return
    parentView.removeView(this)
}

Dengan aman tidak akan melakukan apa pun jika Tampilan ini adalah nol, tampilan induk adalah nol, atau tampilan induk bukan merupakan ViewGroup

Gibolt
sumber
1

Saya menemukan perbaikan lain:

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

Di sini saya hanya memiliki pernyataan if memeriksa apakah tampilan memiliki orangtua dan jika tidak membuat dialog baru, mengatur contentView dan menampilkan dialog dalam metode "createAlgorithmDialog ()" saya.

Ini juga mengatur tombol positif dan negatif (tombol ok dan batal) dengan onClickListeners.

Joshua Orotayo
sumber
0

Anda dapat menggunakan metode ini untuk memeriksa apakah suatu pandangan memiliki anak atau tidak.

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

Kasus saya berbeda tampilan anak sudah memiliki tampilan induk saya menambahkan tampilan anak di dalam tampilan induk ke induk yang berbeda. contoh kode di bawah ini

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

Dan saya menggembungkan pandangan ini dan menambahkan ke LinearLayout lain, kemudian saya menghapus LinaarLayout dari tata letak di atas dan mulai bekerja

kode di bawah ini memperbaiki masalah:

<?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" />
Irfan
sumber
0

Masalah saya terkait dengan banyak jawaban lain, tetapi alasan yang sedikit berbeda karena perlu melakukan perubahan ... Saya mencoba untuk mengubah suatu Kegiatan menjadi Fragmen. Jadi saya memindahkan kode mengembang dari onCreate ke onCreateView, tapi saya lupa untuk mengonversi dari setContentView ke metode mengembang, dan IllegalStateException yang sama membawa saya ke halaman ini.

Saya mengubah ini:

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

untuk ini:

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

Itu memecahkan masalah.

Daniel Gibby
sumber