{"record":{"id":"7a0ac62981f5c8ac","repo":"AvaloniaUI/Avalonia","slug":"unable-to-obtain-anativewindow","errorCode":null,"errorMessage":"Unable to obtain ANativeWindow","messagePattern":"Unable to obtain ANativeWindow","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs","lineNumber":18,"sourceCode":"using System;\nusing System.Runtime.InteropServices;\nusing System.Runtime.Versioning;\nusing Avalonia.Platform;\n\nnamespace Avalonia.Android.Platform.SkiaPlatform\n{\n    unsafe class AndroidFramebuffer : ILockedFramebuffer\n    {\n        private IntPtr _window;\n\n        public AndroidFramebuffer(InvalidationAwareSurfaceView surface, double scaling)\n        {\n            if(surface == null)\n                throw new ArgumentNullException(nameof(surface));\n            _window = (surface as IPlatformHandle).Handle;\n            if (_window == IntPtr.Zero)\n                throw new Exception(\"Unable to obtain ANativeWindow\");\n            ANativeWindow_Buffer buffer;\n            var rc = new ARect()\n            {\n                right = ANativeWindow_getWidth(_window),\n                bottom = ANativeWindow_getHeight(_window)\n            };\n            Size = new PixelSize(rc.right, rc.bottom);\n            ANativeWindow_lock(_window, &buffer, &rc);\n\n            (Format, AlphaFormat, RowBytes) = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565 ?\n                (PixelFormat.Rgb565, AlphaFormat.Opaque, buffer.stride * 2) :\n                (PixelFormat.Rgba8888, AlphaFormat.Premul, buffer.stride * 4);\n\n            Address = buffer.bits;\n\n            Dpi = new Vector(96, 96) * scaling;\n        }\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs#L1-L36","documentation":"Thrown by the AndroidFramebuffer constructor when the underlying InvalidationAwareSurfaceView exposes a zero (IntPtr.Zero) native window handle. The framebuffer needs a valid ANativeWindow pointer to lock and render pixels; a null handle means the Android Surface has not been created yet (or was already destroyed) at the time Avalonia tried to draw.","triggerScenarios":"Constructing AndroidFramebuffer via FramebufferManager.Lock() when (surface as IPlatformHandle).Handle returns IntPtr.Zero. This happens if rendering is requested before SurfaceCreated fired, after SurfaceDestroyed fired, or if the SurfaceView was never properly attached to the window hierarchy.","commonSituations":"Activity paused/resumed lifecycle races where a draw is scheduled between SurfaceDestroyed and SurfaceCreated; embedding AvaloniaView in a ViewPager/RecyclerView where the view is detached; calling TopLevel.RequestAnimationFrame or forcing a render before the surface is ready; custom embedding that bypasses InvalidationAwareSurfaceView's lifecycle hooks.","solutions":["Ensure rendering is gated on the SurfaceWindowCreated event and suppressed on SurfaceWindowDestroyed — let InvalidationAwareSurfaceView drive the render loop, do not call render externally before surface creation.","If embedding AvaloniaView, make sure it is attached to a visible window (added to the view hierarchy and laid out) before any draw is requested.","Avoid forcing framebuffer locks during Activity.onPause/onResume transitions; defer rendering until the host signals the surface is valid.","Upgrade Avalonia.Android — newer versions may short-circuit rendering when InternalView or its handle is invalid instead of throwing."],"exampleFix":"// before\n_topLevelImpl.Surfaces.OfType<IFramebufferPlatformSurface>().First().CreateFramebufferRenderTarget();\n\n// after — only render when the surface is actually ready\nif (_surfaceView.IsSurfaceValid)\n{\n    _topLevelImpl.Surfaces.OfType<IFramebufferPlatformSurface>().First().CreateFramebufferRenderTarget();\n}","handlingStrategy":"validation","validationCode":"// before locking the framebuffer, confirm the surface has a valid window handle\nvar handle = (surfaceView as IPlatformHandle)?.Handle ?? IntPtr.Zero;\nif (handle == IntPtr.Zero) return; // surface not ready — skip this frame","typeGuard":"static bool HasValidNativeWindow(InvalidationAwareSurfaceView? view)\n    => view is IPlatformHandle h && h.Handle != IntPtr.Zero;","tryCatchPattern":"// framebuffer lock is internal; the actionable guard is to suppress rendering\n// when the surface isn't ready rather than catching after the fact.\nif (!HasValidNativeWindow(internalView)) return;","preventionTips":["Drive rendering from the surface lifecycle events (SurfaceWindowCreated/Destroyed), not from external timers.","Do not force a draw before the Activity's view is attached and laid out.","Null/zero-check the surface handle before any render request in custom embedding code.","Upgrade Avalonia.Android to pick up lifecycle-hardened render gating."],"tags":["android","rendering","surface","lifecycle","skia"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}