---
title: "AndroidExternalSurface"
description: "Provides a dedicated drawing [Surface] as a separate layer positioned by default behind the
window holding the [AndroidExternalSurface] composable. Because [AndroidExternalSurface] uses a
separate window layer, graphics composition is handled by the system compositor which can bypass
the GPU and provide better performance and power usage characteristics compared to
[AndroidEmbeddedExternalSurface]. It is therefore recommended to use [AndroidExternalSurface]
over [AndroidEmbeddedExternalSurface] whenever possible.

The [Surface] provided can be used to present content that's external to Compose, such as a video
stream (from a camera or a media player), OpenGL, Vulkan...The provided [Surface] can be rendered
into using a thread different from the main thread.

The z-ordering of the surface can be controlled using the [zOrder] parameter:
- [AndroidExternalSurfaceZOrder.Behind]: positions the surface behind the window
- [AndroidExternalSurfaceZOrder.MediaOverlay]: positions the surface behind the window but above other [AndroidExternalSurfaceZOrder.Behind] surfaces
- [AndroidExternalSurfaceZOrder.OnTop]: positions the surface above the window

The drawing surface is opaque by default, which can be controlled with the [isOpaque] parameter.
When the surface is transparent, you may need to change the z-order to see something behind the
surface.

To start rendering, the caller must first acquire the [Surface] when it's created. This is
achieved by providing the [onInit] lambda, which allows the caller to register an appropriate
[AndroidExternalSurfaceScope.onSurface] callback. The [onInit] lambda can also be used to
initialize/cache resources needed once a surface is available.

After acquiring a surface, the caller can start rendering into it. Rendering into a surface can
be done from any thread.

It is recommended to register the [SurfaceScope.onChanged] and [SurfaceScope.onDestroyed]
callbacks to properly handle the lifecycle of the surface and react to dimension changes. You
must ensure that the rendering thread stops interacting with the surface when the
[SurfaceScope.onDestroyed] callback is invoked.

If a [surfaceSize] is specified (set to non-[IntSize.Zero]), the surface will use the specified
size instead of the layout size of this composable. The surface will be stretched at render time
to fit the layout size. This can be used for instance to render at a lower resolution for
performance reasons."
type: "composable"
---

<div class='type'>Composable Function</div>


<a id='references'></a>

<div class='sourceset sourceset-android'>Android</div>


```kotlin
@Composable
fun AndroidExternalSurface(
    modifier: Modifier = Modifier,
    isOpaque: Boolean = true,
    surfaceSize: IntSize = IntSize.Zero,
    zOrder: AndroidExternalSurfaceZOrder = AndroidExternalSurfaceZOrder.Behind,
    isSecure: Boolean = false,
    onInit: AndroidExternalSurfaceScope.() -> Unit,
)
```


Provides a dedicated drawing `Surface` as a separate layer positioned by default behind the
window holding the `AndroidExternalSurface` composable. Because `AndroidExternalSurface` uses a
separate window layer, graphics composition is handled by the system compositor which can bypass
the GPU and provide better performance and power usage characteristics compared to
`AndroidEmbeddedExternalSurface`. It is therefore recommended to use `AndroidExternalSurface`
over `AndroidEmbeddedExternalSurface` whenever possible.

The `Surface` provided can be used to present content that's external to Compose, such as a video
stream (from a camera or a media player), OpenGL, Vulkan...The provided `Surface` can be rendered
into using a thread different from the main thread.

The z-ordering of the surface can be controlled using the `zOrder` parameter:
- `AndroidExternalSurfaceZOrder.Behind`: positions the surface behind the window
- `AndroidExternalSurfaceZOrder.MediaOverlay`: positions the surface behind the window but above other `AndroidExternalSurfaceZOrder.Behind` surfaces
- `AndroidExternalSurfaceZOrder.OnTop`: positions the surface above the window

The drawing surface is opaque by default, which can be controlled with the `isOpaque` parameter.
When the surface is transparent, you may need to change the z-order to see something behind the
surface.

To start rendering, the caller must first acquire the `Surface` when it's created. This is
achieved by providing the `onInit` lambda, which allows the caller to register an appropriate
`AndroidExternalSurfaceScope.onSurface` callback. The `onInit` lambda can also be used to
initialize/cache resources needed once a surface is available.

After acquiring a surface, the caller can start rendering into it. Rendering into a surface can
be done from any thread.

It is recommended to register the `SurfaceScope.onChanged` and `SurfaceScope.onDestroyed`
callbacks to properly handle the lifecycle of the surface and react to dimension changes. You
must ensure that the rendering thread stops interacting with the surface when the
`SurfaceScope.onDestroyed` callback is invoked.

If a `surfaceSize` is specified (set to non-`IntSize.Zero`), the surface will use the specified
size instead of the layout size of this composable. The surface will be stretched at render time
to fit the layout size. This can be used for instance to render at a lower resolution for
performance reasons.

#### Parameters

| | |
| --- | --- |
| modifier | Modifier to be applied to the `AndroidExternalSurface` |
| isOpaque | Whether the managed surface should be opaque or transparent. |
| surfaceSize | Sets the surface size independently of the layout size of this `AndroidExternalSurface`. If set to `IntSize.Zero`, the surface size will be equal to the `AndroidExternalSurface` layout size. |
| zOrder | Sets the z-order of the surface relative to its parent window. |
| isSecure | Control whether the surface view's content should be treated as secure, preventing it from appearing in screenshots or from being viewed on non-secure displays. |
| onInit | Lambda invoked on first composition. This lambda can be used to declare a `AndroidExternalSurfaceScope.onSurface` callback that will be invoked when a surface is available. |





## Code Examples
### AndroidExternalSurfaceColors
```kotlin
@Composable
fun AndroidExternalSurfaceColors() {
    AndroidExternalSurface(modifier = Modifier.fillMaxWidth().height(400.dp)) {
        // Resources can be initialized/cached here
        // A surface is available, we can start rendering
        onSurface { surface, width, height ->
            var w = width
            var h = height
            // Initial draw to avoid a black frame
            surface.lockCanvas(Rect(0, 0, w, h)).apply {
                drawColor(Color.Blue.toArgb())
                surface.unlockCanvasAndPost(this)
            }
            // React to surface dimension changes
            surface.onChanged { newWidth, newHeight ->
                w = newWidth
                h = newHeight
            }
            // Cleanup if needed
            surface.onDestroyed {}
            // Render loop, automatically cancelled on surface destruction
            while (true) {
                withFrameNanos { time ->
                    surface.lockCanvas(Rect(0, 0, w, h)).apply {
                        val timeMs = time / 1_000_000L
                        val t = 0.5f + 0.5f * sin(timeMs / 1_000.0f)
                        drawColor(lerp(Color.Blue, Color.Green, t).toArgb())
                        surface.unlockCanvasAndPost(this)
                    }
                }
            }
        }
    }
}
```

