Home > database >  Xamarin Android: Calling Invalidate() inside overridden OnDraw method
Xamarin Android: Calling Invalidate() inside overridden OnDraw method

Time:05-17

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();
    }
}

CodePudding user response:

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

CodePudding user response:

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.

  • Related