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

Android crash when adding a View to a Layout that is already in another Layout #15920

Closed
gerhartz opened this issue Jun 28, 2023 · 5 comments
Closed
Labels
area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Milestone

Comments

@gerhartz
Copy link

gerhartz commented Jun 28, 2023

Description

Maui crashes on Android when you create a View (such as a button), assign it to a Layout, assign that layout to the Content property and then reuse that same control in a 2nd layout. When you assign the 2nd layout to Content property it causes a crash.

The crash results in the error:
Java.Lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

This is not reproducible on iOS but consistently happening on Android (tested on Android 13 but not other versions). Ideally Maui would detach any Views from its parent before adding a View to a different Layout.

Another point is the layout must be assigned to the Content property for this error to happen. For example, if you assign the same control to 2 layouts but only assign 1 layout to Content that is okay. But when you assign the 2nd layout to the Content property it breaks.

Steps to Reproduce

  1. Create new Maui app. File -> New Solution -> Maui App
  2. Create a Layout, such as a VerticalStack and assign it to the page Content
  3. Add a button to the stack and assign the layout to the Content property of the page. Keep a reference to the button.
  4. Create a second VerticalStack containing the same button
  5. Assign the second layout to the Content property

Result: App Crashes with error "Java.Lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first."

Expected: To be able to reassign a button to different layouts without having to manually remove it from previous layouts.

Link to public reproduction project repository

https://github.com/gerhartz/maui_android_crash

Version with bug

7.0.86

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Broken on Android 13, possibly earlier versions

Did you find any workaround?

  1. Manually remove a View from its parent before adding it to another Layout

((Layout)view.Parent)?.Remove(view);

  1. Avoid reassigning a control to a different layout after it has already been added to avoid hitting the IllegalStateException.

  2. Duplicating the control and adding the duplicate to a layout instead of reusing the original can be a workaround, although in some cases this is not feasible to maintain multiple duplicate controls.

Relevant log output

Java.Lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
   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 12324
   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
   at Android.Views.ViewGroup.AddView(View child) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net7.0/android-33/mcw/Android.Views.ViewGroup.cs:line 1999
   at Microsoft.Maui.Handlers.LayoutHandler.SetVirtualView(IView view) in D:\a\_work\1\s\src\Core\src\Handlers\Layout\LayoutHandler.Android.cs:line 43
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.ILayout, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.LayoutViewGroup, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].SetVirtualView(IElement view) in D:\a\_work\1\s\src\Core\src\Handlers\View\ViewHandlerOfT.cs:line 56
   at Microsoft.Maui.Controls.Element.SetHandler(IElementHandler newHandler) in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\Element\Element.Impl.cs:line 69
   at Microsoft.Maui.Controls.Element.set_Handler(IElementHandler value) in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\Element\Element.Impl.cs:line 19
   at Microsoft.Maui.Controls.VisualElement.Microsoft.Maui.IElement.set_Handler(IElementHandler value) in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\VisualElement\VisualElement.Impl.cs:line 303
   at Microsoft.Maui.Platform.ElementExtensions.ToHandler(IElement view, IMauiContext context) in D:\a\_work\1\s\src\Core\src\Platform\ElementExtensions.cs:line 96
   at Microsoft.Maui.Platform.ElementExtensions.ToPlatform(IElement view, IMauiContext context) in D:\a\_work\1\s\src\Core\src\Platform\ElementExtensions.cs:line 127
   at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) in D:\a\_work\1\s\src\Core\src\Handlers\ContentView\ContentViewHandler.Android.cs:line 44
   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 49
   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
   at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 47
   at Microsoft.Maui.PropertyMapper.UpdateProperty(IElementHandler viewHandler, IElement virtualView, String property) in D:\a\_work\1\s\src\Core\src\PropertyMapper.cs:line 72
   at Microsoft.Maui.Handlers.ElementHandler.UpdateValue(String property) in D:\a\_work\1\s\src\Core\src\Handlers\Element\ElementHandler.cs:line 87
   at Microsoft.Maui.Controls.Element.OnPropertyChanged(String propertyName) in D:\a\_work\1\s\src\Controls\src\Core\Element.cs:line 383
   at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 533
   at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 469
   at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value, Boolean fromStyle, Boolean checkAccess) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 391
   at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value) in D:\a\_work\1\s\src\Controls\src\Core\BindableObject.cs:line 365
   at Microsoft.Maui.Controls.ContentPage.set_Content(View value) in D:\a\_work\1\s\src\Controls\src\Core\ContentPage.cs:line 14
   at AndroidCrash.MainPage.Add() in /Users/pgerhartz/Documents/GitHub/maui_android_crash/AndroidCrash/MainPage.xaml.cs:line 34
   at AndroidCrash.MainPage.<.ctor>b__2_0(Object sender, EventArgs args) in /Users/pgerhartz/Documents/GitHub/maui_android_crash/AndroidCrash/MainPage.xaml.cs:line 19
   at Microsoft.Maui.Controls.Button.Microsoft.Maui.Controls.Internals.IButtonElement.PropagateUpClicked() in D:\a\_work\1\s\src\Controls\src\Core\Button.cs:line 278
   at Microsoft.Maui.Controls.ButtonElement.ElementClicked(VisualElement visualElement, IButtonElement ButtonElementManager) in D:\a\_work\1\s\src\Controls\src\Core\ButtonElement.cs:line 85
   at Microsoft.Maui.Controls.Button.SendClicked() in D:\a\_work\1\s\src\Controls\src\Core\Button.cs:line 253
   at Microsoft.Maui.Controls.Button.Microsoft.Maui.IButton.Clicked() in D:\a\_work\1\s\src\Controls\src\Core\HandlerImpl\Button\Button.Impl.cs:line 24
   at Microsoft.Maui.Handlers.ButtonHandler.OnClick(IButton button, View v) in D:\a\_work\1\s\src\Core\src\Handlers\Button\ButtonHandler.Android.cs:line 153
   at Microsoft.Maui.Handlers.ButtonHandler.ButtonClickListener.OnClick(View v) in D:\a\_work\1\s\src\Core\src\Handlers\Button\ButtonHandler.Android.cs:line 174
   at Android.Views.View.IOnClickListenerInvoker.n_OnClick_Landroid_view_View_(IntPtr jnienv, IntPtr native__this, IntPtr native_v) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net7.0/android-33/mcw/Android.Views.View.cs:line 2285
   at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_V(_JniMarshal_PPL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 121
  --- End of managed Java.Lang.IllegalStateException stack trace ---
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:5248)
	at android.view.ViewGroup.addView(ViewGroup.java:5077)
	at android.view.ViewGroup.addView(ViewGroup.java:5017)
	at android.view.ViewGroup.addView(ViewGroup.java:4989)
	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:31)
	at android.view.View.performClick(View.java:7506)
	at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1219)
	at android.view.View.performClickInternal(View.java:7483)
	at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
	at android.view.View$PerformClick.run(View.java:29357)
	at android.os.Handler.handleCallback(Handler.java:942)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7884)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

  --- End of managed Java.Lang.IllegalStateException stack trace ---
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:5248)
	at android.view.ViewGroup.addView(ViewGroup.java:5077)
	at android.view.ViewGroup.addView(ViewGroup.java:5017)
	at android.view.ViewGroup.addView(ViewGroup.java:4989)
	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:31)
	at android.view.View.performClick(View.java:7506)
	at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1219)
	at android.view.View.performClickInternal(View.java:7483)
	at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
	at android.view.View$PerformClick.run(View.java:29357)
	at android.os.Handler.handleCallback(Handler.java:942)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7884)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
@gerhartz gerhartz added the t/bug Something isn't working label Jun 28, 2023
@Eilon Eilon added the area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter label Jun 30, 2023
@XamlTest XamlTest added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed labels Jul 31, 2023
@XamlTest
Copy link

Verified this on Visual Studio Enterprise 17.7.0 Preview 5.0. Repro on Android 13.0-API33 and Windows 11 .NET 8, not repro on iOS 16.4 with below Project:
AndroidCrash.zip

Exception on Android:
image
Exception on Windows:
image

@mattleibow
Copy link
Member

Tested on macOS and this works. So, it looks like Android and Windows have this issue.

@mattleibow mattleibow added this to the Backlog milestone Nov 29, 2023
@ghost
Copy link

ghost commented Nov 29, 2023

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

@mattleibow
Copy link
Member

This is an intentional change: dotnet/docs-maui#1923

@mattleibow
Copy link
Member

Duplicate of dotnet/docs-maui#1923

@mattleibow mattleibow marked this as a duplicate of dotnet/docs-maui#1923 Feb 2, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Mar 4, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter 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