Skiasharp: Async Await issue System.AccessViolationException

Created on 8 Feb 2017  路  5Comments  路  Source: mono/SkiaSharp

I am getting below exception
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

in Xamarin Forms UWP while doing await Task.Deley(500);
canvas.DrawCircle(point.Item1.X, point.Item1.Y, 10, dotPaint

        private async void OnPainting(object sender, SKPaintSurfaceEventArgs e)
        {
            var canvas = e.Surface.Canvas;

            // scale the canvas up (for higher resolution screens)
            var scale = e.Info.Width / (float)Width;
            canvas.Scale(scale);


            // make the surface nice
            canvas.Clear(SKColors.White);


            // draw the dots
            var dotPaint = new SKPaint
            {
                IsAntialias = true,
                Style = SKPaintStyle.Fill
            };
            foreach (var point in points)
            {
                        await Task.Delay(500);
                dotPaint.Color = point.Item2;
                canvas.DrawCircle(point.Item1.X, point.Item1.Y, 10, dotPaint);
            }


            // draw the instructions
            var textPaint = new SKPaint
            {
                IsAntialias = true,
                Color = SKColors.Brown,
                Style = SKPaintStyle.Fill,
                TextSize = 48,
                TextAlign = SKTextAlign.Center,
                Typeface = SKTypeface.FromFamilyName("Arial", SKTypefaceStyle.Bold)
            };
            canvas.DrawText("tap 4 dots!", (float)Width / 2, 50, textPaint);
            // give it a border
            textPaint.Style = SKPaintStyle.Stroke;
            textPaint.StrokeWidth = 1;
            textPaint.Color = SKColors.White;
            canvas.DrawText("tap 4 dots!", (float)Width / 2, 50, textPaint);
        }

Most helpful comment

It is the await... you can't await in the paint method as the entire method needs to happen in a single go. If it awaits, then the canvas will be destroyed before the await is finished.

Basically, the paint operation is a UI step, and the await part causes the control to leave the UI, during which the paint is seen as done by the OS.

For this type of operation - animation - you might have to have a state and a collection of circles:

// to start the animation (field)
int counter = 0;

```csharp
// then start the animation
Task.Run(async () =>
{
// loop through the points
while (points.Count > counter)
{
await Task.Delay(500);

    // ask the UI to repaint
    Device.BeginInvokeOnMainThread(() =>
    {
        counter++;
        canvasView.InvalidateSurface();
    });
}

});

```csharp
// change the for loop to do this (note the .Take method)
foreach (var point in points.Take(counter))
{
    ...
}

What you are doing here is to actually "perform the animation" in a counter, and then only drawing the dots so far. This way the paint method runs to completion. After each "animation" step, request a repaint.

All 5 comments

It is the await... you can't await in the paint method as the entire method needs to happen in a single go. If it awaits, then the canvas will be destroyed before the await is finished.

Basically, the paint operation is a UI step, and the await part causes the control to leave the UI, during which the paint is seen as done by the OS.

For this type of operation - animation - you might have to have a state and a collection of circles:

// to start the animation (field)
int counter = 0;

```csharp
// then start the animation
Task.Run(async () =>
{
// loop through the points
while (points.Count > counter)
{
await Task.Delay(500);

    // ask the UI to repaint
    Device.BeginInvokeOnMainThread(() =>
    {
        counter++;
        canvasView.InvalidateSurface();
    });
}

});

```csharp
// change the for loop to do this (note the .Take method)
foreach (var point in points.Take(counter))
{
    ...
}

What you are doing here is to actually "perform the animation" in a counter, and then only drawing the dots so far. This way the paint method runs to completion. After each "animation" step, request a repaint.

I have started using this library from today only and it's looks promising. Is it completed for using in Xamarin Forms? Because I am having difficulty finding small examples/tutorials for Xamarin Forms.
Thanks.

It is fully functional in Forms. There is a "big" forms sample here: https://github.com/mono/SkiaSharp/tree/master/samples/FormsSample

This particular issue has nothing to do with SkiaSharp directly, it is more the actual memory you are writing to is being discarded when you await. If you were using the native platform bits, this will still occur.

The difficulty is that this is a fairly new library - the managed binding. As time goes on, more and more tutorials will appear.

There is also this simple app: https://github.com/mattleibow/SkiaSharpDemo

And the blog to go with it: https://blog.xamarin.com/drawing-with-skiasharp/

@mattleibow Thanks for the samples. Its like magic added to Xamarin Forms. So many design possibility's are open.
https://github.com/mono/SkiaSharp/tree/master/samples/FormsSample
https://github.com/mattleibow/SkiaSharpDemo.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

corliss picture corliss  路  4Comments

loketha picture loketha  路  4Comments

NotOfficer picture NotOfficer  路  3Comments

michaldobrodenka picture michaldobrodenka  路  3Comments

joreg picture joreg  路  4Comments