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

Pancake view crashes app on dynamic app theme switch: PancakeViewRenderer Cannot access a disposed object #168

Open
alexeystrakh opened this issue Jun 11, 2021 · 7 comments

Comments

@alexeystrakh
Copy link

I've recently started to use a dynamic theme for a Xamarin.Forms app with AppThemeBinding. Unfortunately, the Pancake view crashes sometimes after first, other times after several theme switches via the system menu. I can reliably reproduce it in my Xamarin.Forms Android app. The UI is as simple as below:

<pancakeview:PancakeView BackgroundColor="{AppThemeBinding Dark={StaticResource TileBackground_Dark}, Light={StaticResource TileBackground_Light}}"> ...

The crash points to Android.Views.View.SetBackgroundColor in PancakeViewRenderer. I'm changing the theme via the context system menu (pulled from the top of the screen):

[AppCenterCrashes] System.ObjectDisposedException: Cannot access a disposed object.
[AppCenterCrashes] Object name: 'Xamarin.Forms.PancakeView.Droid.PancakeViewRenderer'.
[AppCenterCrashes] at Java.Interop.JniPeerMembers.AssertSelf (Java.Interop.IJavaPeerable self) [0x00029] in <c2283cbfa9df4045adcb3fe5939ebddf>:0
[AppCenterCrashes] at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00000] in <c2283cbfa9df4045adcb3fe5939ebddf>:0
[AppCenterCrashes] at Android.Views.View.SetBackgroundColor (Android.Graphics.Color color) [0x0001e] in /Users/builder/azdo/_work/1/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-30/mcw/Android.Views.View.cs:22288
[AppCenterCrashes] at Xamarin.Forms.Platform.Android.VisualElementRenderer`1[TElement].UpdateBackgroundColor () [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:491
[AppCenterCrashes] at Xamarin.Forms.Platform.Android.VisualElementRenderer`1[TElement].OnElementPropertyChanged (System.Object sender, System.ComponentModel.PropertyChangedEventArgs e) [0x00017] in D:\a\1\s\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:368
[AppCenterCrashes] at Xamarin.Forms.PancakeView.Droid.PancakeViewRenderer.OnElementPropertyChanged (System.Object sender, System.ComponentModel.PropertyChangedEventArgs e) [0x00009] in <a1f8c5f59e794e2b99a9a6be6aa81de2>:0
[AppCenterCrashes] at (wrapper delegate-invoke) <Module>.invoke_void_object_PropertyChangedEventArgs(object,System.ComponentModel.PropertyChangedEventArgs)
[AppCenterCrashes] at Xamarin.Forms.BindableObject.OnPropertyChanged (System.String propertyName) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:266
[AppCenterCrashes] at Xamarin.Forms.Element.OnPropertyChanged (System.String propertyName) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:362
[AppCenterCrashes] at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x00114] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:510
[AppCenterCrashes] at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x00173] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:446
[AppCenterCrashes] at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:383
[AppCenterCrashes] at Xamarin.Forms.AppThemeBinding.ApplyCore () [0x00018] in D:\a\1\s\Xamarin.Forms.Core\AppThemeBinding.cs:47
[AppCenterCrashes] at Xamarin.Forms.AppThemeBinding.<.ctor>b__2_1 () [0x00000] in D:\a\1\s\Xamarin.Forms.Core\AppThemeBinding.cs:10
[AppCenterCrashes] at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in /Users/builder/azdo/_work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36
[AppCenterCrashes] at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in /Users/builder/azdo/_work/1/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-30/mcw/Java.Lang.IRunnable.cs:90
[AppCenterCrashes] at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.39(intptr,intptr)
**System.ObjectDisposedException:** 'Cannot access a disposed object.
Object name: 'Xamarin.Forms.PancakeView.Droid.PancakeViewRenderer'.'[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.ObjectDisposedException: Cannot access a disposed object.
[mono-rt] Object name: 'Xamarin.Forms.PancakeView.Droid.PancakeViewRenderer'.
[mono-rt] at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.39(intptr,intptr)
[mono-rt] at (wrapper native-to-managed) Android.Runtime.DynamicMethodNameCounter.39(intptr,intptr)

As you can see, there is no custom code in the stack trace, only the PancakeViewRenderer.
How can I fix the issue?

@rocharodo
Copy link

Hi,
I am also getting the "Cannot access a disposed object" error.

Do you have a fix for this yet?

It crashes the app.

07-29 17:58:30.377 D/Mono ( 6330): GC_TAR_BRIDGE bridges 961 objects 64690 opaque 26667 colors 961 colors-bridged 961 colors-visible 961 xref 1 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.23ms tarjan 69.09ms scc-setup 0.41ms gather-xref 0.05ms xref-setup 0.01ms cleanup 4.56ms
07-29 17:58:30.377 D/Mono ( 6330): GC_BRIDGE: Complete, was running for 226.07ms
07-29 17:58:30.377 D/Mono ( 6330): GC_MINOR: (Concurrent start) time 95.01ms, stw 105.28ms promoted 389K major size: 8416K in use: 7169K los size: 20480K in use: 15970K
07-29 17:58:30.377 D/Mono ( 6330): GC_MAJOR_CONCURRENT_START: (LOS overflow)
07-29 17:58:30.453 D/Mono ( 6330): GC_BRIDGE waiting for bridge processing to finish
07-29 17:58:30.651 I/mum.mopcommerc( 6330): Explicit concurrent copying GC freed 14316(681KB) AllocSpace objects, 2(48KB) LOS objects, 68% free, 8MB/26MB, paused 281us total 178.959ms
07-29 17:58:30.655 D/Mono ( 6330): GC_BRIDGE waiting for bridge processing to finish
07-29 17:58:30.672 D/Mono ( 6330): GC_TAR_BRIDGE bridges 1247 objects 19497 opaque 7470 colors 1076 colors-bridged 1074 colors-visible 1074 xref 152 cache-hit 0 cache-semihit 0 cache-miss 2 setup 0.37ms tarjan 24.96ms scc-setup 1.09ms gather-xref 0.08ms xref-setup 0.02ms cleanup 1.92ms
07-29 17:58:30.672 D/Mono ( 6330): GC_BRIDGE: Complete, was running for 216.45ms
07-29 17:58:30.672 D/Mono ( 6330): GC_MAJOR_CONCURRENT_FINISH: (finishing) time 311.18ms, stw 77.42ms los size: 12288K in use: 548K
07-29 17:58:30.673 D/Mono ( 6330): GC_MAJOR_SWEEP: major size: 8368K in use: 6956K
07-29 17:58:30.683 I/Choreographer( 6330): Skipped 30 frames! The application may be doing too much work on its main thread.
07-29 17:58:31.684 D/ViewRootImpl@ccb841dMainActivity: ViewPostIme pointer 0
07-29 17:58:32.029 D/ViewRootImpl@ccb841dMainActivity: ViewPostIme pointer 1
07-29 17:58:32.267 D/ViewRootImpl@ccb841dMainActivity: ViewPostIme pointer 0
07-29 17:58:32.701 D/ViewRootImpl@ccb841dMainActivity: ViewPostIme pointer 1
07-29 17:58:33.070 D/ViewRootImpl@ccb841dMainActivity: ViewPostIme pointer 0
07-29 17:58:33.153 D/ViewRootImpl@ccb841dMainActivity: ViewPostIme pointer 1
Thread finished: #5
System.ObjectDisposedException: 'Cannot access a disposed object.
Object name: 'Xamarin.Forms.PancakeView.Droid.PancakeViewRenderer'.'
Thread started: #20
The thread 0x5 has exited with code 0 (0x0).
Thread finished: #7
The thread 0x7 has exited with code 0 (0x0).
Thread finished: #8
The thread 0x8 has exited with code 0 (0x0).
Thread finished: #12
The thread 0xc has exited with code 0 (0x0).
Thread finished: #9
The thread 0x9 has exited with code 0 (0x0).
Thread finished: #15
The thread 0xf has exited with code 0 (0x0).
Thread finished: #11
The thread 0xb has exited with code 0 (0x0).
Thread finished: #13
The thread 0xd has exited with code 0 (0x0).
Thread finished: #20
The thread 0x14 has exited with code 0 (0x0).
Thread finished: #16
The thread 0x10 has exited with code 0 (0x0).
Thread finished: #14
The thread 0xe has exited with code 0 (0x0).
Thread finished: #6
The thread 0x6 has exited with code 0 (0x0).

@Boukri
Copy link

Boukri commented Aug 12, 2021

Hello,
I'm having the same issue
=>System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'Xamarin.Forms.PancakeView.Droid.PancakeView Renderer'.'
Im using Xamarin forms shell, and the error appears when I navigate to page with Shell.Current.GoToAsync("ClientDetailsView"); Then when I press other tab and back to Client Details Page the app crashed.
EDIT

    <ScrollView Padding="20,0" >
        <pv:PancakeView  Style="{DynamicResource PancakeViewMainContainerStyle}"   Margin="20">
            <StackLayout>
                <Label Text="معلومات العميل" Style="{DynamicResource Header}"/>
                <Frame Style="{DynamicResource EntryFrameStyle}">
                    <StackLayout Orientation="Horizontal">
                        <Label VerticalTextAlignment="Center" Text="اللقب"/>
                        <material:MaterialTextField Style="{DynamicResource EntryStyle}" InputType="Text"   />
                    </StackLayout>
                </Frame>
                <Frame Style="{DynamicResource EntryFrameStyle}">
                    <StackLayout Orientation="Horizontal">
                        <Label VerticalTextAlignment="Center" Text="الاسم"/>
                        <material:MaterialTextField Style="{DynamicResource EntryStyle}" InputType="Text"   />
                    </StackLayout>
                </Frame>
                <Frame Style="{DynamicResource EntryFrameStyle}">
                    <StackLayout Orientation="Horizontal">
                        <Label VerticalTextAlignment="Center" Text="الهاتف"/>
                        <material:MaterialTextField Style="{DynamicResource EntryStyle}" InputType="Text"   />
                    </StackLayout>

                </Frame>
                <Frame Style="{DynamicResource EntryFrameStyle}">
                    <StackLayout Orientation="Horizontal">
                        <Label VerticalTextAlignment="Center" Text="العنوان"/>
                        <material:MaterialTextField Style="{DynamicResource EntryStyle}" InputType="Text"   />
                    </StackLayout>

                </Frame>
                <Frame Style="{DynamicResource EntryFrameStyle}">
                    <StackLayout Orientation="Horizontal">
                        <Label VerticalTextAlignment="Center" Text="البريد الإلكتروني"/>
                        <material:MaterialTextField Style="{DynamicResource EntryStyle}" InputType="Text"   />
                    </StackLayout>
                </Frame>
                <Button Style="{DynamicResource SaveButtonStyle}"/>
            </StackLayout>
        </pv:PancakeView>            
    </ScrollView>

When i removed the ScrollView No Bug Appears

@marcusts
Copy link

marcusts commented Oct 6, 2021

Same here... please notify me when there is a fix. Thank you!

     async Task SetContent()
     {
        {
           var newView = view ?? await GetDefaultContent().WithoutChangingContext();

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
"Cannot access a disposed object: PancakeViewRenderer" -- works on iOS, crashes on Android
base.Content = newView;
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

           // Raise the current class's post content tasks
           RunPostContentTasks(this).WithoutChangingContext();

           if (
              RunContentTasksAfterAssignment &&
              Content.IsNotNullOrDefault()   &&
              Content is IProvidePostContentTasks_PI contentAsRunningPostContentTasks
           )
           {
              // Raise the *content's* post content tasks
              await contentAsRunningPostContentTasks.RunPostContentTasks(this).WithoutChangingContext();
           }

           await ConsiderSettingContentBindingContext().WithoutChangingContext();
        }
     }

@marcusts
Copy link

marcusts commented Nov 3, 2021

I figured this one out.

I couldn't use @sthewissen's original project because of the scope and complexity. The shared views require compliance with all current versions of various platforms. But they haven't been updated, so the source can't be modified except by Steven himself. Perhaps he'll read this and consider making this small change to his own code, plus updating everything.

I jumped over to the (Rounded Content View)[https://github.com/tomh4/HotTotem.RoundedContentView] here on GitHub because it was similar to the PancaeView, except without the internal gradients. I was both surprised and refreshed that this older library reported the same error as we had all seen: "cannot access a disposed object". But because the library was small, I was able to download the source, including the renderers, and do some active testing. The problem popped up right away:

``
public class RoundedContentViewRenderer : ViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);

        ////////////////////////////////////////////////////////////////////////////////////////////////
        // Valid, but the handler survives it, so Element can be valid during PropertyChanged
        ////////////////////////////////////////////////////////////////////////////////////////////////
        if (this.Element == null) return;

        this.Element.PropertyChanged += (sender, e1) =>
        {
            try
            {
                 ////////////////////////////////////////////////////////////////////////////////////////////////
                 // The NativeView is checked for null, but not the Element
                 // The Element is garbage collected unexpectedly, so the earlier check does not catch it.
                 ////////////////////////////////////////////////////////////////////////////////////////////////
                if (NativeView != null)
                {
                    NativeView.SetNeedsDisplay();
                    NativeView.SetNeedsLayout();
                }
            }
            catch (Exception exp)
            {
                Debug.WriteLine("Warning : " + exp.Message);
            }
        };
    }

The solution is in my own Modern App Demo

``
public class RoundedContentViewRenderer : ViewRenderer
{
private static readonly PropertyInfo[] _staticPropInfos;

  static RoundedContentViewRenderer()
  {
      // Gets the public properties of the interface to reduce noise and inadvertent handling
     _staticPropInfos = SharedUtils.Utils.Extensions.GetAllPropInfos<IRoundedContentView>();
  }

  protected override void OnElementChanged( ElementChangedEventArgs<View> e )
  {
     base.OnElementChanged( e );

     if ( Element == null )
     {
        return;
     }

     Element.PropertyChanged += ( sender, args ) =>
                                {
                                   try
                                   {
                                      // My own method for checking if something is null or default
                                      if ( NativeView.IsNotNullOrDefault() &&
                                      // Filter out odd properties that we shouldn't be managing
                                           _staticPropInfos.Any( pi => pi.Name.IsSameAs( args.PropertyName ) ) )
                                      {
                                         ThreadHelper.ConsiderBeginInvokeActionOnMainThread( () =>
                                         {
                                            try
                                            {
                                               // CRITICAL: Check the Element for null
                                               if ( Element.IsNotNullOrDefault() )
                                               {
                                                  NativeView.SetNeedsDisplay();
                                                  NativeView.SetNeedsLayout();
                                               }
                                            }
                                            catch ( ObjectDisposedException )
                                            {
                                               // Bury this error
                                            }
                                         } );
                                      }
                                   }
                                   catch ( Exception exp )
                                   {
                                      Debug.WriteLine( "Warning : " + exp.Message );
                                   }
                                };
  }

The error goes away instantly.

Steps:

(1) Copy the RoundedContentView class into your project from my UI.XamForms Support Library

(2) Copy the Android renderer as is

(3) Copy my modified iOS renderer as well.

@Takudzwamz
Copy link

Hello everyone has anyone found a solution to this? I'm getting this error trying to set BackgroundColor dynamically using Pancakeview.

<Style x:Key="PanCakeStyle" TargetType="pancake:PancakeView">
                <Setter Property="BackgroundColor" Value="{AppThemeBinding Dark={StaticResource colorPanCakeDark}, 
                                                                           Light={StaticResource colorPanCakelight}}" />
            </Style>

@vbalaraju
Copy link

vbalaraju commented Feb 16, 2022

Hi,

I'm facing same issue, it works in iOS but in android app getting crash when I tried to switch another Tabs

System.ObjectDisposedException
Message=Cannot access a disposed object.
Object name: 'Xamarin.Forms.PancakeView.Droid.PancakeViewRenderer'.

Is there any fix for this issue?

@marcusts
Copy link

I solved this by jumping over to another component, the RoundedContentView. If you really need the PancakeView, you will have to absorb all of the project's code and revise both renderers. The problem is that the renderer(s) are dying while still attached to the handlers -- see this part of the code sample:

// CRITICAL: Check the Element for null
if ( Element.IsNotNullOrDefault() )
{
NativeView.SetNeedsDisplay();
NativeView.SetNeedsLayout();
}

Unfortunately, the PancakeView is an elaborate project with many shard libraries that you will find difficult to set up properly. That's why I dropped it.

Best of luck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants