maui
maui copied to clipboard
CarouselView change programmatically Position property or CurrentItem Property throw Java.Lang.IllegalStateException: 'The specified child already has a parent. You must call removeView() on the child's parent first.'
Description
On android platform, when programmatically switching between items in a CarouselView, a Java.Lang.IllegalStateException is thrown: 'The specified child already has a parent. You must call removeView() on the child's parent first.' The bug is floating, it can be reproduced from the code of the attached repository. You need to switch between tabs many times (20 or more) until the error appears. I made a recording of an android emulator.
Steps to Reproduce
- .NET MAUI application that uses a CarouselView and programmatically change Position property many times (20 or more)
- Run on Android
Expected: application works stably Actual: application crashes
https://github.com/dotnet/maui/assets/58216372/e29f31b4-54b8-46ca-97ba-cdf45446d666
Link to public reproduction project repository
https://github.com/kbezzubov/TabViewControl
Version with bug
8.0.40 SR5
Is this a regression from previous behavior?
Yes, this used to work in Xamarin.Forms, Not sure, did not test other versions
Last version that worked well
Unknown/Other
Affected platforms
Android
Affected platform versions
Android 14
Did you find any workaround?
I have a workaround: In the log I see the following lines:
_[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: Java.Lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
[mono-rt] at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop /src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 20830
[mono-rt] at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/ Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 75
[mono-rt] at Android.Views.ViewGroup.AddView(View child) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34 /mcw/Android.Views.ViewGroup.cs:line 2148
[mono-rt] at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 42
[mono-rt] at Microsoft.Maui.Handlers.ContentViewHandler.MapContent(IContentViewHandler handler, IContentView page) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs: line 47
[mono-rt] at Microsoft.Maui.PropertyMapper`2.<>c__DisplayClass5_0[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Handlers .IContentViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v) in D:\a\_work\1\s\src\Core\ src\PropertyMapper.cs:line 172_
From which it follows that the ContentViewHandler and the UpdateContent method need to be corrected. To do this, you can write a custom handler for ContentView, in which the UpdateContent method will look like this:
static void UpdateContent(IContentViewHandler handler)
{
_ = handler.PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class.");
_ = handler.MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class.");
_ = handler.VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class.");
handler.PlatformView.RemoveAllViews();
if (handler.VirtualView.PresentedContent is IView view)
{
var v = view.ToPlatform(handler.MauiContext);
if(v.Parent is ViewGroup viewGroup)
{
if (viewGroup.ChildCount > 0)
{
viewGroup.RemoveView(v);
}
}
handler.PlatformView.AddView(view.ToPlatform(handler.MauiContext));
}
}
In my repository, there is an implementation of this handler. To make sure that this works, you need to uncomment the line in the MauiProgram.cs file where the handler is registered:
#if __ANDROID__
builder.ConfigureMauiHandlers(handlers =>
{
//handlers.AddHandler(typeof(ContentView), typeof(CustomContentViewHandler));
});
#endif
Relevant log output
**Java.Lang.IllegalStateException:** 'The specified child already has a parent. You must call removeView() on the child's parent first.'
**Java.Lang.IllegalStateException:** 'The specified child already has a parent. You must call removeView() on the child's parent first.'
Поток 0xc завершился с кодом 0 (0x0).
Поток 0x6 завершился с кодом 0 (0x0).
Поток 0x9 завершился с кодом 0 (0x0).
Поток 0xd завершился с кодом 0 (0x0).
Поток 0xb завершился с кодом 0 (0x0).
Поток 0x8 завершился с кодом 0 (0x0).
Thread finished: <Thread Pool> #12
Thread finished: <Thread Pool> #6
Thread finished: <Thread Pool> #9
Thread finished: <Thread Pool> #13
Thread finished: <Thread Pool> #11
Thread finished: <Thread Pool> #8
Thread started: <Thread Pool> #14
[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: Java.Lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
[mono-rt] at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 20830
[mono-rt] at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 75
[mono-rt] at Android.Views.ViewGroup.AddView(View child) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Android.Views.ViewGroup.cs:line 2148
[mono-rt] at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 42
[mono-rt] at Microsoft.Maui.Handlers.ContentViewHandler.MapContent(IContentViewHandler handler, IContentView page) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 47
[mono-rt] at Microsoft.Maui.PropertyMapper`2.<>c__DisplayClass5_0[[Microsoft.Maui.IContentView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Handlers.IContentViewHandler, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 172
[mono-rt] at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 47
[mono-rt] at Microsoft.Maui.PropertyMapper.UpdateProperty(IElementHandler viewHandler, IElement virtualView, String property) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 72
[mono-rt] at Microsoft.Maui.Handlers.ElementHandler.UpdateValue(String property) in D:\a\_work\1\s\src\Core\src\Handlers\Element\ElementHandler.cs:line 87
[mono-rt] at Microsoft.Maui.Controls.Element.OnPropertyChanged(String propertyName) in D:\a\_work\1\s\src\Controls\src\Core\Element\Element.cs:line 574
[mono-rt] at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, SetterSpecificity specificity, Boolean silent) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 642
[mono-rt] at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, SetterSpecificity specificity) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 569
[mono-rt] at Microsoft.Maui.Controls.BindingExpression.ApplyCore(Object sourceObject, BindableObject target, BindableProperty property, Boolean fromTarget, SetterSpecificity specificity) in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 163
[mono-rt] at Microsoft.Maui.Controls.BindingExpression.Apply(Object sourceObject, BindableObject target, BindableProperty property, SetterSpecificity specificity) in D:\a\_work\1\s\src\Controls\src\Core\BindingExpression.cs:line 78
[mono-rt] at Microsoft.Maui.Controls.Binding.Apply(Object context, BindableObject bindObj, BindableProperty targetProperty, Boolean fromBindingContextChanged, SetterSpecificity specificity) in D:\a\_work\1\s\src\Controls\src\Core\Binding.cs:line 137
[mono-rt] at Microsoft.Maui.Controls.BindableObject.ApplyBindings(Boolean skipBindingContext, Boolean fromBindingContextChanged) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 665
[mono-rt] at Microsoft.Maui.Controls.BindableObject.BindingContextPropertyChanged(BindableObject bindable, Object oldvalue, Object newvalue) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 684
[mono-rt] at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, SetterSpecificity specificity, Boolean silent) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 644
[mono-rt] at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, SetterSpecificity specificity) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 569
[mono-rt] at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 474
[mono-rt] at Microsoft.Maui.Controls.BindableObject.set_BindingContext(Object value) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 54
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.TemplatedItemViewHolder.Bind(Object itemBindingContext, ItemsView itemsView, Action`1 reportMeasure, Nullable`1 size) in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\TemplatedItemViewHolder.cs:line 80
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.ItemsViewAdapter`2[[Microsoft.Maui.Controls.CarouselView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Handlers.Items.IItemsViewSource, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].BindTemplatedItemViewHolder(TemplatedItemViewHolder templatedItemViewHolder, Object context) in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\Adapters\ItemsViewAdapter.cs:line 152
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.CarouselViewAdapter`2[[Microsoft.Maui.Controls.CarouselView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Handlers.Items.IItemsViewSource, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnBindViewHolder(ViewHolder holder, Int32 position) in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\Adapters\CarouselViewAdapter.cs:line 44
[mono-rt] at AndroidX.RecyclerView.Widget.RecyclerView.Adapter.n_OnBindViewHolder_Landroidx_recyclerview_widget_RecyclerView_ViewHolder_I(IntPtr jnienv, IntPtr native__this, IntPtr native_holder, Int32 position) in C:\a\_work\1\s\generated\androidx.recyclerview.recyclerview\obj\Release
et6.0-android\generated\src\AndroidX.RecyclerView.Widget.RecyclerView.cs:line 581
[mono-rt] at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLI_V(_JniMarshal_PPLI_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, Int32 p1) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 176
[mono-rt] --- End of managed Java.Lang.IllegalStateException stack trace ---
[mono-rt] java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
[mono-rt] at android.view.ViewGroup.addViewInner(ViewGroup.java:5275)
[mono-rt] at android.view.ViewGroup.addView(ViewGroup.java:5104)
[mono-rt] at android.view.ViewGroup.addView(ViewGroup.java:5044)
[mono-rt] at android.view.ViewGroup.addView(ViewGroup.java:5016)
[mono-rt] at crc645d80431ce5f73f11.CarouselViewAdapter_2.n_onBindViewHolder(Native Method)
[mono-rt] at crc645d80431ce5f73f11.CarouselViewAdapter_2.onBindViewHolder(CarouselViewAdapter_2.java:48)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7678)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7761)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6582)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6848)
[mono-rt] at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
[mono-rt] at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
[mono-rt] at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
[mono-rt] at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
[mono-rt] at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
[mono-rt] at android.os.Handler.handleCallback(Handler.java:958)
[mono-rt] at android.os.Handler.dispatchMessage(Handler.java:99)
[mono-rt] at android.os.Looper.loopOnce(Looper.java:205)
[mono-rt] at android.os.Looper.loop(Looper.java:294)
[mono-rt] at android.app.ActivityThread.main(ActivityThread.java:8177)
[mono-rt] at java.lang.reflect.Method.invoke(Native Method)
[mono-rt] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
[mono-rt] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
[mono-rt]
[mono-rt] --- End of managed Java.Lang.IllegalStateException stack trace ---
[mono-rt] java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
[mono-rt] at android.view.ViewGroup.addViewInner(ViewGroup.java:5275)
[mono-rt] at android.view.ViewGroup.addView(ViewGroup.java:5104)
[mono-rt] at android.view.ViewGroup.addView(ViewGroup.java:5044)
[mono-rt] at android.view.ViewGroup.addView(ViewGroup.java:5016)
[mono-rt] at crc645d80431ce5f73f11.CarouselViewAdapter_2.n_onBindViewHolder(Native Method)
[mono-rt] at crc645d80431ce5f73f11.CarouselViewAdapter_2.onBindViewHolder(CarouselViewAdapter_2.java:48)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7678)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7761)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6582)
[mono-rt] at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6848)
[mono-rt] at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
[mono-rt] at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
[mono-rt] at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
[mono-rt] at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
[mono-rt] at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
[mono-rt] at android.os.Handler.handleCallback(Handler.java:958)
[mono-rt] at android.os.Handler.dispatchMessage(Handler.java:99)
[mono-rt] at android.os.Looper.loopOnce(Looper.java:205)
[mono-rt] at android.os.Looper.loop(Looper.java:294)
[mono-rt] at android.app.ActivityThread.main(ActivityThread.java:8177)
[mono-rt] at java.lang.reflect.Method.invoke(Native Method)
[mono-rt] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
[mono-rt] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
[mono-rt]
Hi I'm an AI powered bot that finds similar issues based off the issue title.
Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!
Open similar issues:
- [Android] CarouselView: VirtualView cannot be null here, when clearing and adding items on second navigation (#22035), similarity score: 0.84
Closed similar issues:
- CarouselView - The specified child already has a parent. You must call removeView() on the child's parent first (#20852), similarity score: 0.86
- Android crash when adding a View to a Layout that is already in another Layout (#15920), similarity score: 0.82
- [regression/8.0.0-rc1] [Android] Removing ItemSource item in ListView causes crash (#17028), similarity score: 0.81
- Page with TitleView crashes on Android when navigating back to it from Shell Tab (#4506), similarity score: 0.81
Note: You can give me feedback by thumbs upping or thumbs downing this comment.
Yeah, I have a very similar message to that (on switching a Flyout to an already existing page with a TitleView) - not sure if related or just co-incidental. https://github.com/dotnet/maui/issues/21037
Verified this issue with Visual Studio 17.10 Preview 7.0(8.0.408.0.21&8.0.3). Can repro on Android platform with sample project.