Skip to content

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

Closed

Description

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    area-layoutStackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenterplatform/android 🤖s/triagedIssue has been revieweds/verifiedVerified / Reproducible Issue ready for Engineering Triaget/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions