source

지정한 하위 항목에 이미 상위 항목이 있습니다.먼저 자녀의 부모(Android)에서 removeView()를 호출해야 합니다.

goodcode 2022. 8. 8. 20:03
반응형

지정한 하위 항목에 이미 상위 항목이 있습니다.먼저 자녀의 부모(Android)에서 removeView()를 호출해야 합니다.

두 레이아웃을 자주 바꿔야 합니다.에러는, 이하의 레이아웃으로 발생하고 있습니다.

처음에 레이아웃을 호출했을 때는 에러가 발생하지 않고 문제 없습니다.다음으로 다른 레이아웃(공백)을 호출한 후 레이아웃을 다시 호출하면 다음 오류가 발생합니다.

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

전에도 이런 질문을 한 적이 있다는 것을 알지만, 제 경우에는 도움이 되지 않았습니다.

에러 메세지가 「You do you do」라고 표시됩니다.

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

의론을 간단히 통과시키다

attachtoroot = false

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

recycleverview에서 오류를 검색하려고 왔는데 해결 방법이 작동하지 않았습니다(분명히).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));

false가 아닌 attach to root를 사용하여 fragment를 true로 커밋하려고 할 때 다음과 같은 메시지가 나타납니다.

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

실행 후:

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

됐다.

frameLayout.addView(배너애드뷰);<----- 이 행에 에러가 발생했을 경우는, 다음과 같이 실행합니다.

if (bannerAdView.getParent() != null)

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

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

먼저 상위 보기에서 하위 보기를 제거해야 합니다.

자바 코틀린은 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)
}

이 보기가 null, 상위 보기가 null 또는 상위 보기가 View Group이 아닌 경우 아무 작업도 하지 않습니다.

다른 솔루션이 다음과 같이 동작하지 않는 경우:

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

fragment의 onCreateView에서 싱글 뷰 또는 뷰 그룹 중 무엇을 반환하는지 확인합니다.내 경우 fragment의 xml 루트에 뷰페이저가 있고 뷰페이저를 반환하고 있었는데 레이아웃에 뷰그룹을 추가했을 때 뷰그룹이 아닌 뷰그룹을 반환해야 한다고 업데이트하지 않았습니다.

저의 오류는 다음과 같이 뷰를 정의하는 것입니다.

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으로 심플화

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

이 경우 제약 조건 레이아웃에 대해 "root"라는 ID가 지정되었습니다. 이 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>

제 경우, 문제는 제가 부모 뷰를 부풀린 것이 원인입니다.<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

떼어내면 문제 해결에 도움이 되었다.

아래 코드로 해결했습니다.

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

주의: 에러는 fragment 클래스에서 발생한 것으로, onDestroy 메서드를 이렇게 덮어쓰면 해결할 수 있었습니다.

attachToRoot 파라미터 false를 전달하기만 하면 됩니다.

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

보기를 이미 추가했는지 확인합니다.

if (textView.getParent() == null)
    layout.addView(textView);
if(tv!= null){
    ((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}

제 경우 다음과 같이 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
}

해결책은 하위 보기(rv) 대신 상위 보기(v)를 반환하는 것이었습니다.

다른 해결책을 찾았습니다.

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

여기에서는 뷰에 상위 항목이 있는지 확인하고 뷰에 새 대화상자가 생성되지 않은 경우 contentView를 설정하고 "createAlgorithmDialog()" 메서드로 대화상자를 표시합니다.

또한 긍정 및 부정 버튼(OK 및 취소 버튼)을 onClickListeners로 설정합니다.

제 문제는 다른 많은 답변과 관련이 있지만, 변경을 해야 하는 이유는 조금 다릅니다.액티비티를 fragment로 변환하려고 했습니다.따라서 벌룬 코드를 onCreate에서 onCreateView로 이동했는데 setContentView에서 벌룬 메서드로 변환하는 것을 잊어버렸습니다.이 페이지에서 같은 IlgalStateException을 실행하면 이 페이지가 나타납니다.

이것을 변경했습니다.

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

다음과 같이 입력합니다.

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

그것으로 문제가 해결되었다.

해서 제가 도 같은 생각을 했는데. 같은 생각.같은뷰를 추가하려고 했습니다.NativeAdView다중 다수에게에FrameLayouts별도의 관점이 해소, 다른생성하여 해결합니다 뷰를.NativeAdView각 각각에 대해서에FrameLayout, Thanks,고마워요.

제 경우, recycleerView에서 동작하는 어댑터가 있었는데, 어댑터에 전달된 아이템은 자체 뷰가 있는 아이템이었습니다.

무엇이 요구되었다는 단지 LinearLayout기 위한 행동으로 컨테이너에 대한 모든 아이템이 제가 일을 하고 있었습니다 잠깐 그 품목에 지정된 위치 안에필요한 것은 전달되는 모든아이템의컨테이너 역할을 하는 선형 Layout뿐이었기 때문에 제가 하고 있던 것은 아이템을 안쪽의 지정된 위치에서 잡는 것이었습니다.onBindViewHolder그리고 그 LinearLayout이 전시되었다에 넣어라.LinearLayout에 추가합니다 이를그런 다음 이야기.이것이 표시되었습니다.

문서의 기본 사항을 확인해보니

아이템이 화면에서 스크롤되어도 RecycleerView에 의해 뷰가 파괴되지 않는다.

따라서 아이템은 한 방향으로 스크롤을 한 후 반대 방향으로 이동하면 빠르게 표시 아이템이 파괴되지 않습니다.즉, 아이템은 아직 Linear Layout 컨테이너와 관련지어져 있고, 제 쪽에서는 다른 컨테이너에 부착하려고 합니다.그 결과 아이는 이미 부모가 되어 버렸습니다.

나의 해결 방법 지정한 항목 하더라도요, 나는 변수에 저장한 다음 전화를 배정해 줘 부모 확인하는 것이었다.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_discloss_discloss의 내용:

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

사실, 부모에게 추가하기 전에 아이에게 부모가 있는지 물어보는 것과 같습니다.

너희가 제안한 건 다 해봤지만 난 운이 없었어.

그러나 모든 바인딩 초기화를 onCreate에서 onCreateView로 이동하여 수정했습니다.

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

이동처

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

ViewBinding을 사용하는 경우 올바른 바인딩을 참조하고 있는지 확인하십시오.

액티비티 내에서 커스텀대화상자를 부풀리려고 할 때 다음과 같은 문제가 발생했습니다.

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.

이 메서드를 사용하여 보기에 하위 항목이 있는지 여부를 확인할 수 있습니다.

public static boolean hasChildren(ViewGroup viewGroup) {
    return viewGroup.getChildCount() > 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" />

액티비티와 프래그먼트에 데이터 바인딩을 사용하고 있을 때의 일입니다.

fragment - onCreateView에서는 기존 방식으로 inplater를 사용하여 레이아웃을 부풀릴 수 있으며 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 이름을 변경하십시오.

언급URL : https://stackoverflow.com/questions/28071349/the-specified-child-already-has-a-parent-you-must-call-removeview-on-the-chil

반응형