[Android] Fix crash adding items to the CollectionView (#7670)
authorJavier Suárez Ruiz <javiersuarezruiz@hotmail.com>
Mon, 2 Dec 2019 16:20:03 +0000 (17:20 +0100)
committerE.Z. Hart <hartez@users.noreply.github.com>
Mon, 2 Dec 2019 16:20:03 +0000 (09:20 -0700)
* Fixed 7510 - Crash adding items to the CollectionView on Android

* Removed code used for testing

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7510.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.Android/CollectionView/AdapterNotifier.cs

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7510.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7510.cs
new file mode 100644 (file)
index 0000000..b94d9aa
--- /dev/null
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+       [Category(UITestCategories.CollectionView)]
+#endif
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Github, 7510, "CollectionView crashes on adding item", PlatformAffected.All)]
+       public class Issue7510 : TestContentPage
+       {
+               public Issue7510()
+               {
+                       Title = "Issue 7510";
+                       BindingContext = new Issue7510ModelViewModel();
+               }
+
+               protected override void OnAppearing()
+               {
+                       if (this.BindingContext is Issue7510ModelViewModel vm)
+                       {
+                               vm.Init();
+                       }
+
+                       base.OnAppearing();
+               }
+
+               protected override void Init()
+               {
+                       var infoLabel = new Label
+                       {
+                               Text = "If you press the button and there is no crash, everything goes correctly."
+                       };
+
+                       var addButton = new Button
+                       {
+                               Text = "Add items",
+                               AutomationId = "AddBtn"
+                       };
+
+                       addButton.SetBinding(Button.CommandProperty, "MoreCommand");
+
+                       var collectionView = new CollectionView
+                       {
+                               AutomationId = "Collection",
+                               SelectionMode = SelectionMode.None,
+                               ItemTemplate = CreateDataTemplate()
+                       };
+
+                       collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Items");
+
+                       var stack = new StackLayout();
+
+                       stack.Children.Add(infoLabel);
+                       stack.Children.Add(addButton);
+                       stack.Children.Add(collectionView);
+
+                       Content = stack;
+               }
+
+               private DataTemplate CreateDataTemplate()
+               {
+                       DataTemplate template = new DataTemplate(() =>
+                       {
+                               var grid = new Grid() { Padding = new Thickness(0), Margin = 0, RowSpacing = 0, ColumnSpacing = 0 };
+
+                               grid.RowDefinitions.Clear();
+                               grid.ColumnDefinitions.Clear();
+                               grid.Children.Clear();
+
+                               var cell = new Label();
+                               cell.SetBinding(Label.TextProperty, "Title");
+                               grid.Children.Add(cell, 0, 0);
+
+                               return grid;
+                       });
+
+                       return template;
+               }
+       }
+
+       [Preserve(AllMembers = true)]
+       public class Issue7510Model
+       {
+               public Guid Id { get; set; }
+               public string Title { get; set; }
+       }
+
+       [Preserve(AllMembers = true)]
+       public class Issue7510ModelViewModel : BindableObject
+       {
+               private ObservableCollection<Issue7510Model> _items;
+
+               public ObservableCollection<Issue7510Model> Items
+               {
+                       get { return _items; }
+                       set
+                       {
+                               _items = value;
+                               OnPropertyChanged();
+                       }
+               }
+
+               public Command MoreCommand => new Command(async () => await LoadMore());
+
+               private async Task LoadMore()
+               {
+                       await Task.Delay(100);
+
+                       var postCount = Items.Count();
+
+                       for (var i = 0; i < 20; i++)
+                       {
+                               Items.Add(new Issue7510Model { Id = Guid.NewGuid(), Title = $"Added Item {postCount + i}" });
+                               Debug.WriteLine(postCount + i);
+                       }
+               }
+
+               internal void Init()
+               {
+                       var posts = new List<Issue7510Model>();
+
+                       for (var i = 0; i < 20; i++)
+                       {
+                               posts.Add(new Issue7510Model { Id = Guid.NewGuid(), Title = $"Item {i}" });
+                       }
+
+                       Items = new ObservableCollection<Issue7510Model>(posts);
+               }
+       }
+}
\ No newline at end of file
index 2884d68..6e3464d 100644 (file)
       <DependentUpon>Issue7886.xaml</DependentUpon>
     </Compile>
     <Compile Include="$(MSBuildThisFileDirectory)Issue7898.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Issue7510.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
index cea6d23..386ad8d 100644 (file)
@@ -14,42 +14,58 @@ namespace Xamarin.Forms.Platform.Android
 
                public void NotifyDataSetChanged()
                {
-                       _adapter.NotifyDataSetChanged();
+                       if (IsValidAdapter())
+                               _adapter.NotifyDataSetChanged();
                }
 
                public void NotifyItemChanged(IItemsViewSource source, int startIndex)
                {
-                       _adapter.NotifyItemChanged(startIndex);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemChanged(startIndex);
                }
 
                public void NotifyItemInserted(IItemsViewSource source, int startIndex)
                {
-                       _adapter.NotifyItemInserted(startIndex);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemInserted(startIndex);
                }
 
                public void NotifyItemMoved(IItemsViewSource source, int fromPosition, int toPosition)
                {
-                       _adapter.NotifyItemMoved(fromPosition, toPosition);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemMoved(fromPosition, toPosition);
                }
 
                public void NotifyItemRangeChanged(IItemsViewSource source, int start, int end)
                {
-                       _adapter.NotifyItemRangeChanged(start, end);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemRangeChanged(start, end);
                }
 
                public void NotifyItemRangeInserted(IItemsViewSource source, int startIndex, int count)
                {
-                       _adapter.NotifyItemRangeInserted(startIndex, count);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemRangeInserted(startIndex, count);
                }
 
                public void NotifyItemRangeRemoved(IItemsViewSource source, int startIndex, int count)
                {
-                       _adapter.NotifyItemRangeRemoved(startIndex, count);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemRangeRemoved(startIndex, count);
                }
 
                public void NotifyItemRemoved(IItemsViewSource source, int startIndex)
                {
-                       _adapter.NotifyItemRemoved(startIndex);
+                       if (IsValidAdapter())
+                               _adapter.NotifyItemRemoved(startIndex);
+               }
+
+               internal bool IsValidAdapter()
+               {
+                       if (_adapter == null || _adapter.IsDisposed())
+                               return false;
+
+                       return true;
                }
        }
-}
\ No newline at end of file
+}