Search code examples
androidandroid-jetpack-composeandroid-view

Compose AndroidView is not rendered on older phones (Android 6 / 21 API, Samsung S5) after returning to alive Activity (onStart, onResume)


I use SurfaceView in Compose using AndroidView for camera preview.

It works fine but I noticed an issue on older phone Samsung S5 (Android 21 API):

When I press home button (not back button) and then I return back to the app from launcher (onStart, onResume) then the camera preview is not updated (some dark background, mb last camera frame is just displayed). Though on Pixel Emulator Android 21 API it seems to work fine:

Scaffold { innerPadding ->

    // camera preview:

    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { SurfaceView(it) },
    )

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(innerPadding)
    ) {
       /// UI / controls
    }
}

Then I tried to call SurfaceView.invalidate() inside Composable onStart event and it worked fine after that - camera preview is always updated after returning to the activity:

var surfaceView by remember {
    mutableStateOf<SurfaceView?>(null)
}

LifecycleEventEffect(event = Lifecycle.Event.ON_START) {
    surfaceView?.invalidate()
}

Scaffold { innerPadding ->

    // camera preview:

    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { SurfaceView(it).also { surfaceView = it } },
    )

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(innerPadding)
    ) {
       /// UI / controls
    }
}

So without my additional "invalidate" temporary fix it only works if I launch the app for the first time (Activity onCreate is called) or when I switch between screens which means AndroidView leaves the composition and there will be a new one when returning navigation back to this screen again.

On newer modern phones - Samsung S22 (Android 14), Samsung S10 (Android 12) - I can't reproduce this issue, so fix is not needed in this case.

Why does it happen like this? Is it a bug of Compose for older phones?

p.s. all versions of Compose/Kotlin/GradlePlugin libs are the latest:

androidDesugarJdkLibs = "2.0.4"
androidGradlePlugin = "8.2.2"
androidxActivity = "1.8.2"
androidxAppCompat = "1.6.1"
androidxBrowser = "1.7.0"
androidxComposeBom = "2024.01.00"
androidxComposeCompiler = "1.5.8"
androidxComposeMaterial3 = "1.2.0-rc01"
androidxComposeRuntimeTracing = "1.0.0-beta01"
androidxConstraintLayoutCompose = "1.0.1"
androidxCore = "1.12.0"
androidxCoreSplashscreen = "1.0.1"
androidxDataStore = "1.0.0"
androidxEspresso = "3.5.1"
androidxHiltNavigationCompose = "1.1.0"
androidxLifecycle = "2.7.0"
androidxMacroBenchmark = "1.2.3"
androidxMetrics = "1.0.0-beta01"
androidxNavigation = "2.7.6"
androidxPagingCompose = "3.2.1"
androidxProfileinstaller = "1.3.1"
androidxStartup = "1.1.1"
androidxTestCore = "1.5.0"
androidxTestExt = "1.1.5"
androidxTestRules = "1.5.0"
androidxTestRunner = "1.5.2"
androidxTracing = "1.2.0"
androidxUiAutomator = "2.2.0"
androidxWindowManager = "1.2.0"
androidxWork = "2.9.0"
appUpdateKtx = "2.1.0"
billingKtx = "6.1.0"
coil = "2.5.0"
constraintlayout = "2.1.4"
exifinterface = "1.3.7"
firebaseAds = "22.6.0"
firebaseBom = "32.7.1"
firebaseCrashlyticsPlugin = "2.9.9"
firebasePerfPlugin = "1.4.2"
flexbox = "3.0.0"
glide = "1.0.0-beta01"
gmsPlugin = "4.4.0"
googlePlaces = "3.3.0"
hilt = "2.50"
hiltExt = "1.1.0"
junit = "1.1.5"
junit4 = "4.13.2"
kotlin = "1.9.22"
kotlinxCoroutines = "1.7.3"
kotlinxDatetime = "0.5.0"
kotlinxSerializationJson = "1.6.0"
kotlinxSerializationProtobuf = "1.6.2"
ksp = "1.9.22-1.0.17"
libPhoneNumber = "8.13.0"
lifecycleProcess = "2.7.0"
lint = "31.2.2"
localbroadcastmanager = "1.1.0"
mapsCompose = "2.14.0"
material = "1.11.0"
okhttpBom = "4.10.0"
playServicesLocation = "21.1.0"
playServicesMaps = "18.2.0"
preferenceKtx = "1.2.1"
protobuf = "3.24.4"
protobufPlugin = "0.9.4"
pusher = "2.4.4"
recyclerview = "1.3.2"
retrofit = "2.9.0"
retrofitKotlinxSerializationJson = "1.0.0"
reviewKtx = "2.0.1"
room = "2.6.1"
sdk = "21"
secrets = "2.0.1"
swiperefreshlayout = "1.1.0"
timber = "5.0.1"
turbine = "1.0.0"
lifecycleService = "2.7.0"
userMessagingPlatform = "2.2.0"

Solution

  • As a fix I have used View.invalidate() function on each on start lifecycle event:

    LifecycleEvent(event = Lifecycle.Event.ON_START) { owner ->
        surfaceView.invalidate()
    }