While trying to inflate a FragmentDialog containing a RecyclerView, I’m having this “The specified child already has a parent. You must call removeView() on the child’s parent first.” error.
Here’s the code from my DialogFragment:
public class MyDialogFragment extends AppCompatDialogFragment { private static final String DATA = "data"; private MyDialogFragment.MyDialogFragmentListener listener; private ArrayList<MyArrayList> mArrayListData; public static MyDialogFragment newInstance(ArrayList<MyArrayList> ArrayListData) { Bundle args = new Bundle(); MyDialogFragment fragment = new MyDialogFragment(); args.putParcelableArrayList(DATA, ArrayListData); fragment.setArguments(args); return fragment; } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { if (getArguments() != null) { mArrayListData = getArguments().getParcelableArrayList(DATA); } AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); builder.setView(createRecyclerView(mArrayListData)) .setTitle(requireContext().getString(R.string.title)) .setPositiveButton(requireContext().getString(R.string.ok_button), null); Dialog dialog = builder.create(); /* Option set cause key board doesn't appear */ dialog.show(); Objects.requireNonNull(dialog.getWindow()).clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); dialog.setCanceledOnTouchOutside(false); return dialog; } @Override public void onResume() { super.onResume(); final AlertDialog MyAlertDialog = (AlertDialog) getDialog(); if (MyAlertDialog != null) { Button positiveButton = MyAlertDialog.getButton(Dialog.BUTTON_POSITIVE); positiveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ... dismiss(); } }); } } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); try { listener = (MyDialogFragment.MyDialogFragmentListener) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + "must implement ExampleDialogListener"); } } public interface MyDialogFragmentListener { void MyDialogFragmentListenerReturn(ArrayList<MyArrayList> ArrayListData); } private RecyclerView createRecyclerView(final ArrayList<MyArrayList> ArrayListData){ LayoutInflater inflater = requireActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.fragmentLayout, null, false); RecyclerView MyRecyclerView = view.findViewById(R.id.recyclerViewId); MyRecyclerAdapter myAdapter = new MyRecyclerAdapter (getActivity(), ArrayListData); MyRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); MyRecyclerView.setAdapter(myAdapter); myAdapter.setOnItemClickListener(new MyRecyclerAdapter.OnItemClickListener() { @Override public void onReturnValue(int position, int value) { mArrayListData.get(position).setValue(value); } }); return MyRecyclerView; } }
My recycler adapter:
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.InsideRecyclerHolder> { private final Context mContext; private ArrayList<MyArrayList> mArrayListData; private MyRecyclerAdapter.OnItemClickListener mListener; MyRecyclerAdapter(Context context, ArrayList<MyArrayList> ArrayListData) { mContext = context; mArrayListData = RecyclerCarUpdateList; } @NonNull @Override public MyRecyclerAdapter.InsideRecyclerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater myInflater = LayoutInflater.from(mContext); View myOwnView = myInflater.inflate(R.layout.layout_recycler, parent, false); return new MyRecyclerAdapter.InsideRecyclerHolder(myOwnView, mListener); } @Override public void onBindViewHolder(@NonNull MyRecyclerAdapter.InsideRecyclerHolder holder, int position) { MyArrayList currentItem = mArrayListData.get(position); holder.t1.setText(currentItem.getFirstValue()); holder.e1.setHint(currentItem.getSecondValue()); } @Override public int getItemCount() { return mArrayListData.size(); } public interface OnItemClickListener { void onReturnValue(int position, int newValue); } public void setOnItemClickListener(MyRecyclerAdapter.OnItemClickListener listener) { mListener = listener; } static class InsideRecyclerHolder extends RecyclerView.ViewHolder { final TextView t1; final EditText e1; InsideRecyclerHolder(@NonNull View itemView, final OnItemClickListener mListener) { super(itemView); t1 = itemView.findViewById(R.id.textValue); e1 = itemView.findViewById(R.id.editTextValue); e1.setImeOptions(EditorInfo.IME_ACTION_DONE); e1.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (mListener != null) { int position = getAdapterPosition(); if (position != RecyclerView.NO_POSITION) { if (!e1.getText().toString().isEmpty()) { listener.onReturnValue(position, Integer.parseInt(e1.getText().toString())) } } } } @Override public void afterTextChanged(Editable s) { } }); } } }
And here’s the stack:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. at android.view.ViewGroup.addViewInner(ViewGroup.java:4915) at android.view.ViewGroup.addView(ViewGroup.java:4746) at android.view.ViewGroup.addView(ViewGroup.java:4718) at androidx.appcompat.app.AlertController.setupCustomContent(AlertController.java:657) at androidx.appcompat.app.AlertController.setupView(AlertController.java:475) at androidx.appcompat.app.AlertController.installContent(AlertController.java:233) at androidx.appcompat.app.AlertDialog.onCreate(AlertDialog.java:279) at android.app.Dialog.dispatchOnCreate(Dialog.java:403) at android.app.Dialog.show(Dialog.java:302) at com.myself.myapp.MyDialogFragment.onCreateDialog(MyDialogFragment.java:61) at androidx.fragment.app.DialogFragment.onGetLayoutInflater(DialogFragment.java:419) at androidx.fragment.app.Fragment.performGetLayoutInflater(Fragment.java:1484) at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356) at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497) at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447) at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849) at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413) at android.os.Handler.handleCallback(Handler.java:789) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:169) at android.app.ActivityThread.main(ActivityThread.java:6578) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
It points the issue to the “dialog.show();” of my DialogFragment. I have to admit that I’m quite lost whit is. I have another DialogFragment that works the same way with no issue.
Advertisement
Answer
I solved my issue, I originaly thought it came from my java code but it was an xml layout issue …
My DialogFrament layout was like that:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" android:backgroundTint="#FF8200" android:orientation="vertical" android:padding="16dp" tools:context=".MyDialogFragment "> <TextView android:id="@+id/textViewId" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:textSize="16sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerViewId" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textViewId" /> </androidx.constraintlayout.widget.ConstraintLayout>
and I just needed to use the RecyclerView as a sole element of the layout:
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/recyclerViewId" android:layout_width="match_parent" android:layout_height="match_parent" android:backgroundTint="#FF8200" android:nestedScrollingEnabled="false" android:padding="16dp" tools:context=".MyDialogFragment " app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />