Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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.' #22504

Open
kbezzubov opened this issue May 18, 2024 · 3 comments
Labels
area-controls-collectionview CollectionView, CarouselView, IndicatorView migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working

Comments

@kbezzubov
Copy link

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

  1. .NET MAUI application that uses a CarouselView and programmatically change Position property many times (20 or more)
  2. Run on Android

Expected: application works stably
Actual: application crashes

maui-andrioid.mp4

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]
@kbezzubov kbezzubov added the t/bug Something isn't working label May 18, 2024
Copy link
Contributor

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:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

@Eilon Eilon added the area-controls-collectionview CollectionView, CarouselView, IndicatorView label May 18, 2024
@SmartmanApps
Copy link

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. #21037

@Zhanglirong-Winnie Zhanglirong-Winnie added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert labels May 20, 2024
@Zhanglirong-Winnie
Copy link
Collaborator

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.
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-collectionview CollectionView, CarouselView, IndicatorView migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants