dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.17k stars 1.74k forks source link

CarouselView on Android - "Cannot access a disposed object" #21049

Open BrnPer opened 7 months ago

BrnPer commented 7 months ago

Description

On Android, when using a CarouselView and entering and exiting that page a lot of times, sometimes we receive the error: "Cannot access a disposed object" (as seen in the image below).

image

From the call stack of the exception seems that error is here:

When it calls the UpdateVisualState()

https://github.com/dotnet/maui/blob/f8c60532b1744e74cfa6462ea7021fea137a748f/src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs#L286

And here it tries to GetLayoutManager().

https://github.com/dotnet/maui/blob/f8c60532b1744e74cfa6462ea7021fea137a748f/src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs#L354

But it's just a guess. Not 100% sure.

This is the code for CarouselView page:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CarouselViewBugAndroid.CarouselOnePage"
             xmlns:local="clr-namespace:CarouselViewBugAndroid"
             xmlns:behaviors="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:DataType="local:CarouselOneViewModel">
    <ContentPage.Behaviors>
        <behaviors:EventToCommandBehavior
            x:DataType="local:CarouselOneViewModel"
            EventName="Appearing"
            Command="{Binding PageAppearingCommand}" />
    </ContentPage.Behaviors>

    <ContentPage.Resources>
        <DataTemplate x:Key="CustomCategoryTemplate" x:DataType="local:CustomCategory">
            <Label Text="{Binding Name}" />
        </DataTemplate>
        <DataTemplate x:Key="CustomPageTemplate" x:DataType="local:CustomPage">
            <VerticalStackLayout>
                <Label Text="{Binding Id}"></Label>
                <Label Text="{Binding PageName}"></Label>
                <Label Text="{Binding PageContent}"></Label>
                <Label>
                    <Label.FormattedText>
                        <FormattedString>
                            <Span Text="I have "></Span>
                            <Span Text="{Binding WordsLength}"></Span>
                            <Span Text=" words."></Span>
                        </FormattedString>
                    </Label.FormattedText>
                </Label>
                <Label Text="{Binding PageContent}"></Label>
                <Label Text="{Binding Id}" Margin="0,10,0,0"></Label>
                <Label Text="{Binding PageName}"></Label>
                <Label Text="{Binding PageContent}"></Label>
                <Image
                    Source="dotnet_bot.png"
                    HeightRequest="185"
                    Aspect="AspectFit"
                    SemanticProperties.Description="dot net bot in a race car number eight" />

                <ListView ItemsSource="{Binding Categories}" Margin="0,20,0,0"
                          ItemTemplate="{StaticResource CustomCategoryTemplate}" />

                <Image Margin="0,20,0,0"
                       Source="dotnet_bot.png"
                       HeightRequest="185"
                       Aspect="AspectFit"
                       SemanticProperties.Description="dot net bot in a race car number eight" />
            </VerticalStackLayout>
        </DataTemplate>
    </ContentPage.Resources>
    <ScrollView Margin="10">
        <VerticalStackLayout>
            <Label Text="Hello" VerticalOptions="Center"
                   HorizontalOptions="Start" />
            <IndicatorView
                x:Name="IndicatorView"
                IndicatorColor="Yellow"
                SelectedIndicatorColor="Red"
                HorizontalOptions="Start"
                VerticalOptions="Center" />

            <CarouselView Margin="20"
                          IndicatorView="IndicatorView"
                          Loop="false"
                          ItemsSource="{Binding Pages}"
                          ItemTemplate="{StaticResource CustomPageTemplate}" />
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

This error seems to happen even more where there's a lot of things happening in the ViewModel.

The following video shows the error using the repo provided below. To make it easier to understand, I'm clicking the CarouselOne button and entering CarouselOnePage and then using the shortcut Ctrl + Backspace to go back and doing this a couple of times.

https://github.com/dotnet/maui/assets/26172581/04eabc5c-85db-454c-8388-c75e025d1860

Steps to Reproduce

  1. Get the repo provided and get the main branch.
  2. Start the app on Android.
  3. Click on the CarouselOne button to enter CarouselOnePage.
  4. Then click to go back but then ASAP try to click the button CarouselOne button again.
  5. Do this a couple of times and probably you will found the issue.

Link to public reproduction project repository

https://github.com/BrnPer/CarouselViewBugAndroid.git

Version with bug

8.0.7 SR2

Is this a regression from previous behavior?

No, this is something new

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 12, Android 14 (didn't try in other version)

Did you find any workaround?

After some testing it seems that in the ViewModel not calling Pages.Clear() in the PageAppearingCommand but doing for example Pages = [] on a page disappearing event solves the issue.

Relevant log output

System.ObjectDisposedException
  Message=Cannot access a disposed object.
Object name: 'Microsoft.Maui.Controls.Handlers.Items.MauiCarouselRecyclerView'.
plequere-ms commented 7 months ago

Hitting this as well. Here's a full stack trace.

System.ObjectDisposedException ObjectDisposed_Generic ObjectDisposed_ObjectName_Name, Microsoft.Maui.Controls.Handlers.Items.MauiCarouselRecyclerView

void JniPeerMembers.AssertSelf(IJavaPeerable)
void JniInstanceMethods.InvokeVirtualVoidMethod(string, IJavaPeerable, JniArgumentValue*)
void RecyclerView.RemoveItemDecoration(ItemDecoration)
void MauiCarouselRecyclerView.UpdateItemDecoration()
void MauiCarouselRecyclerView.UpdateItemSpacing()
void MauiRecyclerView<CarouselView, ItemsViewAdapter<CarouselView, IItemsViewSource>, IItemsViewSource>.LayoutPropertyChanged(object sender, PropertyChangedEventArgs propertyChanged)
void WeakNotifyPropertyChangedProxy.OnPropertyChanged(object sender, PropertyChangedEventArgs e)
void BindableObject.OnPropertyChanged(string propertyName)
void BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, SetterSpecificity specificity, bool silent)
void BindableObject.SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, SetterSpecificity specificity)
void BindableObject.SetValue(BindableProperty property, object value)
void DynamicMarkupExtensionBase.SetValue(object target, object value)+() => { }
void MauiExtensions.DispatchIfRequered(IDispatcher dispatcher, Action action)
void DynamicMarkupExtensionBase.SetValue(object target, object value)
void DynamicMarkupExtensionBase.UpdateValue()
void OnScreenSizeExtensionBase.OnMainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)
void DeviceDisplayImplementationBase.OnMainDisplayInfoChanged(DisplayInfoChangedEventArgs) x 2
async void Listener.OnOrientationChanged(int)
void Task.ThrowAsync(Exception, SynchronizationContext)+(object state) => { }
void SyncContext.Post(SendOrPostCallback, object)+() => { }
void RunnableImplementor.Run()
void IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
void JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz)
fabien367 commented 5 months ago

Hello, I had the same problem but I changed my register: Before AddTransient and now AddSingleton It work now

codeinapt commented 5 months ago

I'm having the same problem and I can't find how to solve it.