'Xamarin Android: Calling Invalidate() inside overridden OnDraw method

I am creating a custom renderer, that needs to display whatever I have rendered in my Vulkan engine. For this I have a VulkanSurfaceView, which inherits from MetalKit.MTKView on iOS, and from Android.Views.SurfaceView and ISurfaceHolderCallback on Android.

For iOS I can simply do this, which will draw a new frame continually, as long as the view is in focus:

public class VulkanSurfaceView : MTKView, IVulkanAppHost
{
    ...

    public override void Draw()
    {
        Renderer.Tick();
        base.Draw();
    }
}

However, on Android I have to do this, where I call Invalidate() from within the OnDraw method, else it is only called once. I think this code smells a bit, and I am not sure, if this is the "good" way of doing it. Is my solution okay? If not, does anyone have a better idea?

public class VulkanSurfaceView : SurfaceView, ISurfaceHolderCallback, IVulkanAppHost
{
    ...

    protected override void OnDraw(Canvas? canvas)
    {
        Renderer.Tick();
        base.OnDraw(canvas);
        Invalidate();
    }
}


Solution 1:[1]

Did you try calling setWillNotDraw(false) in your surfaceCreated method ? Refer the link

Solution 2:[2]

Thank you to @ToolmakerSteve.

I created a Timer where I call Invalidate() if a new frame has been requested (by me via a simple bool). For anyone interested I do it like so:

protected override void OnDraw(Canvas? canvas) // Just to show the updated OnDraw-method
{
    Renderer.Tick();
    base.OnDraw(canvas);
}

public void SurfaceCreated(ISurfaceHolder holder)
{
    TickTimer = new System.Threading.Timer(state =>
    {
        AndroidApplication.SynchronizationContext.Send(_ => { if (NewFrameRequested) Invalidate(); }, state);

        try { TickTimer.Change(0, Timeout.Infinite); } catch (ObjectDisposedException) { }

    }, null, 0, Timeout.Infinite);
}

For now it is very simple, but it works and will probably grow. The reason for my initial bad framerate with this method was a misunderstanding of the "dueTime" of the Timer (see Timer Class), which I though was the framerate sought. This is actually the time between frames, which seems obvious now.

As @Bhargavi also kindly mentioned you need to set "setWillNotDraw(false)" if OnDraw is not being called when invalidating the view.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bhargavi
Solution 2 JustAGuyWithALoaf