Xamarin.forms: InvalidOperationException on long-running Android animations

Created on 8 Jan 2019  ·  10Comments  ·  Source: xamarin/Xamarin.Forms

Animating (I am assuming from the stack trace) my Android application seems to cause intermittent crashes.

Error received: List`1+Enumerator[T].MoveNextRare ()
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.

Stack trace:
List1+Enumerator[T].MoveNextRare () List1+Enumerator[T].MoveNext ()
VisualElementTracker.HandleRedrawNeeded (System.Object sender, Xamarin.Forms.Internals.EventArg`1[T] e)
VisualElement.BatchCommit ()
AnimationExtensions.HandleTweenerFinished (System.Object o, System.EventArgs args)
Tweener.b__22_0 (System.Int64 step)
Ticker.SendSignals (System.Int64 step)
Ticker.SendSignals (System.Int32 timestep)
AndroidTicker.OnValOnUpdate (System.Object sender, Android.Animation.ValueAnimator+AnimatorUpdateEventArgs e)
ValueAnimator+IAnimatorUpdateListenerImplementor.OnAnimationUpdate (Android.Animation.ValueAnimator animation)
ValueAnimator+IAnimatorUpdateListenerInvoker.n_OnAnimationUpdate_Landroid_animation_ValueAnimator_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_animation)
(wrapper dynamic-method) System.Object.23(intptr,intptr,intptr)

FYI this is an app I am running specifically on an Amazon Fire TV. Supported devices for the app run on 'Fire OS 6' - which is based on Android 7.1 (API level 25)

There appears to be no specific pattern to the crashes but they don't tend to happen if animations haven't been running for long.

I am running two animations in the app. A simple statistic tile fades labels out and then back in, or there is a RSS feed style ticker which is translated across the screen

Steps to Reproduce

_Fading labels:_

  • This code snippet contains an AbsoluteLayout with child labels. The label text is bound to a 'Tile' object. Both 'title' and 'value' labels are faded out initially. Then the data is updated so the text changes. Then labels are faded back in. This is tracked by a dictionary. This occurs each time a timer elapsed and potentially for multiple 'Tile' objects.
private void AnimateCyclingTile(MobileTile t)
        {
            try
            {
                if (_cyclingTiles.Any(a => a.StyleId == t.ID.ToString()))
                {
                    if (!_cycleTracking.ContainsKey(t.ID))
                    {
                        _cycleTracking.TryAdd(t.ID, 0);
                    }
                    else if (_cycleTracking[t.ID] < (t.AllData.Count - 1))
                    {
                        _cycleTracking[t.ID]++;
                    }
                    else
                    {
                        _cycleTracking[t.ID] = 0;
                    }

                    AbsoluteLayout tile = _cyclingTiles.Single(b => b.StyleId == t.ID.ToString());
                    Label title = (Label)tile.Children.Single(b => b.StyleId == tile.StyleId + "_title");
                    Label value = (Label)tile.Children.Single(b => b.StyleId == tile.StyleId + "_value");

                    // double check key in case tryadd failed
                    if (_cycleTracking.ContainsKey(t.ID))
                    {
                        Task.Run(async () =>
                        {
                            try
                            {
                                // fading labels in/out to cover text size & layout changes
                                title.FadeTo(0, 150);
                                await value.FadeTo(0, 150);

                                int dataIndex = _cycleTracking[t.ID];
                                t.CurrentData = t.AllData.ToList()[dataIndex];
                                t.TextColour = t.CurrentData.TextColour;
                                t.BackgroundColour = t.CurrentData.BackgroundColour;
                                t.DisplayTitle = t.CurrentData.Title;
                                t.DisplayValue = t.CurrentData.Value;

                                title.FadeTo(1, 150);
                                await value.FadeTo(1, 150);
                            }
                            catch (Exception ex)
                            {
                                LogError("AnimateCyclingTile Internal", ex);
                            }
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                LogError("AnimateCyclingTile", ex);
            }
        }

_Translating RSS Feed_

  • This code simply translates an AbsoluteLayout which contains multiple labels with 'title' and 'value' text. The code runs in a loop which simply ends when the layout is made null (handled when the ContentPage closes)

Task.Run(async () => { try { while (_tickerLayout != null) { await AnimateTicker(_tickerLayout); } } catch (Exception ex) { LogError("InitializePageContent - AnimateTicker", ex); } });

private async Task AnimateTicker(AbsoluteLayout layout) { try { // layout dimensions are set in a callback, so ensure that width is set correctly before commencing animation if (layout.Width > 0) { layout.TranslationX = DependencyService.Get<IDeviceSettings>().GetWidth() - 110; await layout.TranslateTo(-layout.Width, 0, (uint)((layout.Width + DependencyService.Get<IDeviceSettings>().GetWidth()) / _tickerSpeedDivider), Easing.Linear); } } catch (Exception ex) { LogError("AnimateTicker", ex); } }

Expected Behavior

Animations should be stable in a long-running app

Actual Behavior

App regularly crashes after some time

Basic Information

  • Version with issue: 3.4.0.1009999
  • Last known good version: None
  • IDE: Visual Studio Enterprise 2017
  • Platform Target Frameworks:

    • Android: 7.1

  • Android Support Library Version: v28.0.0
  • Nuget Packages: None that would interfere with animation
  • Affected Devices: Amazon Fire TV Stick 4K, https://developer.amazon.com/docs/fire-tv/device-specifications.html
animation 🎬 high Android needs-repro ❔ unverified bug

Most helpful comment

@samhouts noticed you added the in-progress label, but the ticket is still 'closed'.

I'm also running into this issue with Xamarin Forms v4.4.0.991757:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
  at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () <0x72dee5f64c + 0x0003f> in <ae34ac7c62754cb597b03df0d25117d3>:0 
  at System.Collections.Generic.List`1+Enumerator[T].MoveNext () <0x72dee5f590 + 0x0009f> in <ae34ac7c62754cb597b03df0d25117d3>:0 
  at Xamarin.Forms.Platform.Android.VisualElementTracker.HandleRedrawNeeded (System.Object sender, Xamarin.Forms.Internals.EventArg`1[T] e) <0x72ddcf1824 + 0x00083> in <4e2bfe51a5614af3a805c091d009f308>:0 
  at Xamarin.Forms.VisualElement.BatchCommit () <0x72de69287c + 0x00087> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.AnimationExtensions.HandleTweenerFinished (System.Object o, System.EventArgs args) <0x72de5d3cb8 + 0x0022b> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Tweener.<Start>b__22_0 (System.Int64 step) <0x72de68ae48 + 0x000d7> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Internals.Ticker.SendSignals (System.Int64 step) <0x72de6b816c + 0x00137> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Internals.Ticker.SendSignals (System.Int32 timestep) <0x72de6b8114 + 0x0004b> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Platform.Android.AndroidTicker.OnValOnUpdate (System.Object sender, Android.Animation.ValueAnimator+AnimatorUpdateEventArgs e) <0x72ddca533c + 0x0002b> in <4e2bfe51a5614af3a805c091d009f308>:0 
  at Android.Animation.ValueAnimator+IAnimatorUpdateListenerImplementor.OnAnimationUpdate (Android.Animation.ValueAnimator animation) <0x72dd6b1600 + 0x0007b> in <9e2ad778f1db4ea69f65ddf84dfabb48>:0 
  at Android.Animation.ValueAnimator+IAnimatorUpdateListenerInvoker.n_OnAnimationUpdate_Landroid_animation_ValueAnimator_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_animation) <0x72dd6b12f4 + 0x00087> in <9e2ad778f1db4ea69f65ddf84dfabb48>:0 
  at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.26(intptr,intptr,intptr)
   --- End of inner exception stack trace --- 

But only periodically, so hard to reproduce or isolate what triggers it

The fix in https://github.com/xamarin/Xamarin.Forms/pull/4932 wasn't accepted because it doesn't relate to the root cause, but could avoid these kinds of crashes

All 10 comments

From the sourceCode the root cause is obvious.
The method HandleRedrawNeeded iterate over _batchedProperties collection.
But this collection can be modified by the method which is called during the iteration during a batch, here.
So the fix is to make a copy of the _batchedProperties collection.

L180 foreach (string propertyName in _batchedProperties)
become foreach (string propertyName in _batchedProperties.ToList())

Thanks @kvpt - created a Pull Request to make the suggested change: #4932

I am also facing same issue. Due to that I am not able to realease my application on play store. So may I know on which xamarin version it will get resolved..
Thanks ..

Same issue...
Xamarin Forms 3.4.0

We need a reproduction of this in order to fix it. The PR may fix it but the code path is hot and we'd rather not create a new array for each pass. Could you please attach a zipped reproduction?

@simonXarios @AmitDKabade @PauchardThomas Since we haven't heard from you in more than 30 days, we hope this issue is no longer affecting you. If it is, please reopen this issue and provide the requested information so that we can look into it further. Thank you!

I'm periodically get same exception ... (Version 4.1.555618)
Stack trace ...
at System.Collections.Generic.List1+Enumerator[T].MoveNextRare () [0x00013] in :0
at System.Collections.Generic.List1+Enumerator[T].MoveNext () [0x0004a] in <ff07eae8184a40a08e79049bbcb31a0e>:0 at Xamarin.Forms.Platform.Android.VisualElementTracker.HandleRedrawNeeded (System.Object sender, Xamarin.Forms.Internals.EventArg1[T] e) [0x00022] in D:\a1\s\Xamarin.Forms.Platform.Android\VisualElementTracker.cs:182
at (wrapper delegate-invoke) System.EventHandler1[Xamarin.Forms.Internals.EventArg1[Xamarin.Forms.VisualElement]].invoke_void_object_TEventArgs(object,Xamarin.Forms.Internals.EventArg1<Xamarin.Forms.VisualElement>) at Xamarin.Forms.VisualElement.BatchCommit () [0x0001c] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:572 at Xamarin.Forms.AnimationExtensions.HandleTweenerFinished (System.Object o, System.EventArgs args) [0x000cb] in D:\a\1\s\Xamarin.Forms.Core\AnimationExtensions.cs:276 at Xamarin.Forms.Tweener.<Start>b__22_0 (System.Int64 step) [0x00095] in D:\a\1\s\Xamarin.Forms.Core\Tweener.cs:103 at Xamarin.Forms.Internals.Ticker.SendSignals (System.Int64 step) [0x0003c] in D:\a\1\s\Xamarin.Forms.Core\Internals\Ticker.cs:117 at Xamarin.Forms.Internals.Ticker.SendSignals (System.Int32 timestep) [0x00014] in D:\a\1\s\Xamarin.Forms.Core\Internals\Ticker.cs:106 at Xamarin.Forms.Platform.Android.AndroidTicker.OnValOnUpdate (System.Object sender, Android.Animation.ValueAnimator+AnimatorUpdateEventArgs e) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.Android\AndroidTicker.cs:81 at Android.Animation.ValueAnimator+IAnimatorUpdateListenerImplementor.OnAnimationUpdate (Android.Animation.ValueAnimator animation) [0x00017] in <b62c3fba3fe848f3bb323dbe33464223>:0 at Android.Animation.ValueAnimator+IAnimatorUpdateListenerInvoker.n_OnAnimationUpdate_Landroid_animation_ValueAnimator_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_animation) [0x00011] in <b62c3fba3fe848f3bb323dbe33464223>:0 at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.26(intptr,intptr,intptr)

@samhouts noticed you added the in-progress label, but the ticket is still 'closed'.

I'm also running into this issue with Xamarin Forms v4.4.0.991757:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
  at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () <0x72dee5f64c + 0x0003f> in <ae34ac7c62754cb597b03df0d25117d3>:0 
  at System.Collections.Generic.List`1+Enumerator[T].MoveNext () <0x72dee5f590 + 0x0009f> in <ae34ac7c62754cb597b03df0d25117d3>:0 
  at Xamarin.Forms.Platform.Android.VisualElementTracker.HandleRedrawNeeded (System.Object sender, Xamarin.Forms.Internals.EventArg`1[T] e) <0x72ddcf1824 + 0x00083> in <4e2bfe51a5614af3a805c091d009f308>:0 
  at Xamarin.Forms.VisualElement.BatchCommit () <0x72de69287c + 0x00087> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.AnimationExtensions.HandleTweenerFinished (System.Object o, System.EventArgs args) <0x72de5d3cb8 + 0x0022b> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Tweener.<Start>b__22_0 (System.Int64 step) <0x72de68ae48 + 0x000d7> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Internals.Ticker.SendSignals (System.Int64 step) <0x72de6b816c + 0x00137> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Internals.Ticker.SendSignals (System.Int32 timestep) <0x72de6b8114 + 0x0004b> in <e97edfbd3986417ab009cb710f4a6a75>:0 
  at Xamarin.Forms.Platform.Android.AndroidTicker.OnValOnUpdate (System.Object sender, Android.Animation.ValueAnimator+AnimatorUpdateEventArgs e) <0x72ddca533c + 0x0002b> in <4e2bfe51a5614af3a805c091d009f308>:0 
  at Android.Animation.ValueAnimator+IAnimatorUpdateListenerImplementor.OnAnimationUpdate (Android.Animation.ValueAnimator animation) <0x72dd6b1600 + 0x0007b> in <9e2ad778f1db4ea69f65ddf84dfabb48>:0 
  at Android.Animation.ValueAnimator+IAnimatorUpdateListenerInvoker.n_OnAnimationUpdate_Landroid_animation_ValueAnimator_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_animation) <0x72dd6b12f4 + 0x00087> in <9e2ad778f1db4ea69f65ddf84dfabb48>:0 
  at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.26(intptr,intptr,intptr)
   --- End of inner exception stack trace --- 

But only periodically, so hard to reproduce or isolate what triggers it

The fix in https://github.com/xamarin/Xamarin.Forms/pull/4932 wasn't accepted because it doesn't relate to the root cause, but could avoid these kinds of crashes

@pver Can you please provide a sample project that demonstrates the issue? Thanks!

Since we haven't heard from you in more than 30 days, we hope this issue is no longer affecting you. If it is, please reopen this issue and provide the requested information so that we can look into it further. Thank you!

Was this page helpful?
0 / 5 - 0 ratings