Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Add check for disposed gesture detector on VisualElementRenderer (#706)
Browse files Browse the repository at this point in the history
  • Loading branch information
hartez authored and samhouts committed Feb 24, 2017
1 parent 5775743 commit fa12ae1
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Bugzilla, 45330, "System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Android.Views.GestureDetector'.", PlatformAffected.Android)]
public class Bugzilla45330 : TestContentPage
{
ObservableCollection<_45330Notification> _feed;

[Preserve(AllMembers = true)]
public class _45330Dto
{
public _45330Dto()
{
Notifications = new ObservableCollection<_45330Notification>();
}

public ObservableCollection<_45330Notification> Notifications { get; set; }
}

[Preserve(AllMembers = true)]
public class _45330Notification
{
public string UniqueId { get; set; }
public DateTime DisplayDate { get; set; }
}

[Preserve(AllMembers = true)]
public class _45330ListCell : ViewCell
{
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();

var item = BindingContext as _45330Notification;
if (item == null) return;

View = new StackLayout()
{
BackgroundColor = Color.Transparent,
Padding = new Thickness(0, 1, 0, 1),
Children = { new Label { Text = item.UniqueId } }
};
}
}

public ObservableCollection<_45330Notification> Feed
{
get { return _feed; }
set
{
_feed = value;
OnPropertyChanged();
}
}

protected override void Init()
{
BindingContext = this;
Feed = MakeNotifications();

var listview = new ListView();
listview.SetBinding(ListView.ItemsSourceProperty, "Feed");
listview.ItemTemplate = new DataTemplate(typeof(_45330ListCell));
listview.IsPullToRefreshEnabled = true;
listview.RefreshCommand = new Command(() =>
{
listview.IsRefreshing = false;
Feed = MakeNotifications();
});

listview.ItemAppearing += (sender, e) =>
{
var currentItem = e.Item as _45330Notification;
if (currentItem == null) return;
var item = Feed.Last();
if (currentItem.UniqueId == item.UniqueId)
{
Feed = MakeNotifications();
}
};

var layout = new StackLayout();

var instructions = new Label { Text = @"The bug can be intermittently reproduced by pulling the list down to refresh it and immediately tapping one of the cells.
Leaving this test page in for reference purposes, and possibly as a base for a future UI test if we get a way to accurately/consistently simulate the events which cause the crash."};

layout.Children.Add(instructions);
layout.Children.Add(listview);

Content = layout;
}

ObservableCollection<_45330Notification> MakeNotifications()
{
var list = new _45330Dto();
for (int i = 0; i < 1000; i++)
{
list.Notifications.Add(new _45330Notification()
{
UniqueId = i.ToString(),
DisplayDate = DateTime.UtcNow
});
}
return list.Notifications;
}

protected override void OnAppearing()
{
base.OnAppearing();
Feed = MakeNotifications();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla43516.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44166.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44338.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla45330.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla47971.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CarouselAsync.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla34561.cs" />
Expand Down Expand Up @@ -584,4 +585,4 @@
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>
6 changes: 6 additions & 0 deletions Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ bool IOnTouchListener.OnTouch(AView v, MotionEvent e)

_gestureListener?.OnTouchEvent(e);

if (_gestureDetector.IsValueCreated && _gestureDetector.Value.Handle == IntPtr.Zero)
{
// This gesture detector has already been disposed, probably because it's on a cell which is going away
return handled;
}

return _gestureDetector.Value.OnTouchEvent(e) || handled;
}

Expand Down

1 comment on commit fa12ae1

@adamped
Copy link
Contributor

@adamped adamped commented on fa12ae1 Mar 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samhouts @hartez While this works, there is still a very very small chance it might be disposed of after the check. As such I recommend doing

return _gestureDetector?.Value?.OnTouchEvent(e) ?? false || handled;

Also the OnTouch is used in the FrameRenderer.cs, which would need something similar.

Please sign in to comment.