¡Hola!
El otro día me ocurrió que en algunas páginas que utilizaban listados (con FlowListView) de 2 columnas , se lanzaba la siguiente excepción:
[MonoDroid] UNHANDLED EXCEPTION: [MonoDroid] System.NullReferenceException: Object reference not set to an instance of an object. [MonoDroid] at Xamarin.Forms.Platform.Android.VisualElementPackager.RemoveChild (Xamarin.Forms.VisualElement view) [0x00007] in D:\agent_work\1\s\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:165 [MonoDroid] at Xamarin.Forms.Platform.Android.VisualElementPackager.OnChildRemoved (System.Object sender, Xamarin.Forms.ElementEventArgs e) [0x0000f] in D:\agent_work\1\s\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:152 [MonoDroid] at Xamarin.Forms.Element.OnChildRemoved (Xamarin.Forms.Element child) [0x0000f] in D:\agent_work\1\s\Xamarin.Forms.Core\Element.cs:387 [MonoDroid] at Xamarin.Forms.VisualElement.OnChildRemoved (Xamarin.Forms.Element child) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\VisualElement.cs:586 [MonoDroid] at Xamarin.Forms.Layout`1[T].OnChildRemoved (Xamarin.Forms.Element child) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\Layout.cs:41 [MonoDroid] at Xamarin.Forms.Layout.OnInternalRemoved (Xamarin.Forms.View view) [0x00012] in D:\agent_work\1\s\Xamarin.Forms.Core\Layout.cs:427 [MonoDroid] at Xamarin.Forms.Layout.InternalChildrenOnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0002f] in D:\agent_work\1\s\Xamarin.Forms.Core\Layout.cs:391 [MonoDroid] at (wrapper delegate-invoke).invoke_void_object_NotifyCollectionChangedEventArgs(object,System.Collections.Specialized.NotifyCollectionChangedEventArgs) [MonoDroid] at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00018] in <3e9b3e26c4694baab3f689687ad40612>:0 [MonoDroid] at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00009] in <3e9b3e26c4694baab3f689687ad40612>:0 [MonoDroid] at System.Collections.ObjectModel.ObservableCollection`1[T].RemoveItem (System.Int32 index) [0x00021] in <3e9b3e26c4694baab3f689687ad40612>:0 [MonoDroid] at System.Collections.ObjectModel.Collection`1[T].Remove (T item) [0x00027] in :0 [MonoDroid] at Xamarin.Forms.ObservableWrapper`2[TTrack,TRestrict].Clear () [0x00030] in D:\agent_work\1\s\Xamarin.Forms.Core\ObservableWrapper.cs:45 [MonoDroid] at DLToolkit.Forms.Controls.FlowListViewInternalCell.UpdateData () [0x0013e] in <8010325400894532bad329e978503ea4>:0 [MonoDroid] at DLToolkit.Forms.Controls.FlowListViewInternalCell.OnBindingContextChanged () [0x00006] in <8010325400894532bad329e978503ea4>:0 [MonoDroid] at Xamarin.Forms.BindableObject.BindingContextPropertyChanged (Xamarin.Forms.BindableObject bindable, System.Object oldvalue, System.Object newvalue) [0x0000f] in D:\agent_work\1\s\Xamarin.Forms.Core\BindableObject.cs:450 [MonoDroid] 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) [0x0011b] in D:\agent_work\1\s\Xamarin.Forms.Core\BindableObject.cs:605 [MonoDroid] at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x0015b] in D:\agent_work\1\s\Xamarin.Forms.Core\BindableObject.cs:399 [MonoDroid] at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value, System.Boolean fromStyle, System.Boolean checkAccess) [0x0005f] in D:\agent_work\1\s\Xamarin.Forms.Core\BindableObject.cs:552 [MonoDroid] at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\BindableObject.cs:92 [MonoDroid] at Xamarin.Forms.BindableObject.set_BindingContext (System.Object value) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\BindableObject.cs:25 [MonoDroid] at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].UpdateContent (TItem content, System.Int32 index, System.Object item) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:614 [MonoDroid] at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].UpdateContent (TItem content, System.Int32 index) [0x0000d] in D:\agent_work\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:629 [MonoDroid] at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].Xamarin.Forms.ITemplatedItemsList .UpdateContent (TItem content, System.Int32 index) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:633 [MonoDroid] at Xamarin.Forms.Platform.Android.ListViewAdapter.GetView (System.Int32 position, Android.Views.View convertView, Android.Views.ViewGroup parent) [0x00155] in D:\agent_work\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:256 [MonoDroid] at Android.Widget.BaseAdapter.n_GetView_ILandroid_view_View_Landroid_view_ViewGroup_ (System.IntPtr jnienv, System.IntPtr native__this, System.Int32 position, System.IntPtr native_convertView, System.IntPtr native_parent) [0x0001a] in <1219ce5aae934ab095dc0e05b2110050>:0 [MonoDroid] at (wrapper dynamic-method) System.Object.43(intptr,intptr,int,intptr,intptr)
Esta excepción sólo se lanzaba en Android y se daba el caso de que sólo ocurría cuando el listado era impar y tenía más de una columna. Por ejemplo, nos imaginamos que tenemos un listado con 17 elementos, pues al movernos a la última fila se lanza la excepción. En concreto se lanza en el método UpdateData de la clase FlowListViewInternalCell:
El problema ocurre cuando se cambia el BindingContext de la última celda (recordamos que se reciclan las celdas) y justo al eliminar los elementos de la fila ( _rootLayoutAuto.Children.Clear()).
Si echamos un vistazo al XAML del FlowListview tenemos lo siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <flv:FlowListView x:Name="flowListView" FlowColumnCount="2" RowHeight="100"> <flv:FlowListView.FlowColumnTemplate> <DataTemplate> <StackLayout CompressedLayout.IsHeadless="true" Margin="5"> <Label VerticalOptions="FillAndExpand" BackgroundColor="Olive" Text="{Binding}"/> </StackLayout> </DataTemplate> </flv:FlowListView.FlowColumnTemplate> </flv:FlowListView> |
El problema que tenemos en nuestro DataTemplate es que estamos añadiendo CompressedLayout en el StackLayout principal, y esto está provocando que al reciclar la celda y eliminar los elementos, se lance la excepción. Realmente no tengo del todo claro el motivo por el que esto sólo ocurre con filas impares, pero si lo eliminamos, no vamos a tener problemas al reciclar la celda:
Este mismo problema lo tenemos también si intentamos limpiar los elementos de un Grid y éstos tienen CompressedLayout.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <ContentPage.Content> <Grid x:Name="MainGrid"> <StackLayout CompressedLayout.IsHeadless="true" Padding="5"> <Label Text="Línea 2"/> <Label Text="Línea 2"/> </StackLayout> </Grid> </ContentPage.Content> |
Dejando de lado que la vista no tiene demasiado sentido y tiene elementos innecesarios, si intentamos limpiar el MainGrid (MainGrid.Children.Clear()), va a lanzar excepción:
[MonoDroid] UNHANDLED EXCEPTION: [MonoDroid] System.NullReferenceException: Object reference not set to an instance of an object. [MonoDroid] at Xamarin.Forms.Platform.Android.VisualElementPackager.RemoveChild (Xamarin.Forms.VisualElement view) [0x00007] in D:\agent_work\1\s\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:165 [MonoDroid] at Xamarin.Forms.Platform.Android.VisualElementPackager.OnChildRemoved (System.Object sender, Xamarin.Forms.ElementEventArgs e) [0x0000f] in D:\agent_work\1\s\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:152 [MonoDroid] at Xamarin.Forms.Element.OnChildRemoved (Xamarin.Forms.Element child) [0x0000f] in D:\agent_work\1\s\Xamarin.Forms.Core\Element.cs:387 [MonoDroid] at Xamarin.Forms.VisualElement.OnChildRemoved (Xamarin.Forms.Element child) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\VisualElement.cs:586 [MonoDroid] at Xamarin.Forms.Layout`1[T].OnChildRemoved (Xamarin.Forms.Element child) [0x00000] in D:\agent_work\1\s\Xamarin.Forms.Core\Layout.cs:41 [MonoDroid] at Xamarin.Forms.Layout.OnInternalRemoved (Xamarin.Forms.View view) [0x00012] in D:\agent_work\1\s\Xamarin.Forms.Core\Layout.cs:427 [MonoDroid] at Xamarin.Forms.Layout.InternalChildrenOnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0002f] in D:\agent_work\1\s\Xamarin.Forms.Core\Layout.cs:391 [MonoDroid] at (wrapper delegate-invoke).invoke_void_object_NotifyCollectionChangedEventArgs(object,System.Collections.Specialized.NotifyCollectionChangedEventArgs) [MonoDroid] at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00018] in <3e9b3e26c4694baab3f689687ad40612>:0 [MonoDroid] at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00009] in <3e9b3e26c4694baab3f689687ad40612>:0 [MonoDroid] at System.Collections.ObjectModel.ObservableCollection`1[T].RemoveItem (System.Int32 index) [0x00021] in <3e9b3e26c4694baab3f689687ad40612>:0 [MonoDroid] at System.Collections.ObjectModel.Collection`1[T].Remove (T item) [0x00027] in :0 [MonoDroid] at Xamarin.Forms.ObservableWrapper`2[TTrack,TRestrict].Clear () [0x00030] in D:\agent_work\1\s\Xamarin.Forms.Core\ObservableWrapper.cs:45 [MonoDroid] at ExceptionFlowListview.MainPage.OnAppearing () [0x00008] in /Users/luismarcos/Documents/Samples/untitled folder/ExceptionFlowListview/ExceptionFlowListview/MainPage.xaml.cs:22 [MonoDroid] at Xamarin.Forms.Page.SendAppearing () [0x00024] in D:\agent_work\1\s\Xamarin.Forms.Core\Page.cs:307 [MonoDroid] at Xamarin.Forms.Platform.Android.PageRenderer.OnAttachedToWindow () [0x00027] in D:\agent_work\1\s\Xamarin.Forms.Platform.Android\Renderers\PageRenderer.cs:42 [MonoDroid] at Android.Views.View.n_OnAttachedToWindow (System.IntPtr jnienv, System.IntPtr native__this) [0x00009] in <1219ce5aae934ab095dc0e05b2110050>:0 [MonoDroid] at (wrapper dynamic-method) System.Object.22(intptr,intptr)
Seguramente el problema esté relacionado con que al usar CompressedLayout se elimina la capa y no encuentre la referencia para eliminarlo. En cualquier caso este problema sólo lo encontramos en versiones de Xamarin Forms anteriores a la 3 y puesto que CompressedLayout se introdujo en la 2.5, seguramente no te afecte 🙂
¡Un saludo!