Funky issue I've got. I'm using `AndroidView` wit...
# compose-android
c
Funky issue I've got. I'm using
AndroidView
with a
SurfaceView
If I have an
if
statement to show/hide the AndroidView... it renders the first time, but if the if statement flips to false and true again, the AndroidView won't render. 🧵
Copy code
@Composable
fun MyAndroidView() {
  AndroidView(
      factory = { ctx ->
        SurfaceView(ctx).apply {
          Log.e("TEST", "apply")
          this.holder.addCallback(
              object : SurfaceHolder.Callback {
                override fun surfaceCreated(holder: SurfaceHolder) {
                  Log.e("TEST", "created")
                }

                override fun surfaceChanged(
                    holder: SurfaceHolder,
                    format: Int,
                    width: Int,
                    height: Int
                ) {
                  Log.e("TEST", "changed")
                }

                override fun surfaceDestroyed(holder: SurfaceHolder) {
                  Log.e("TEST", "destroyed")
                }
              })
        }
      })

}
The logs I get initially:
Copy code
apply
created
changed
changed
then when my if statement flips to false
Copy code
destroyed
then when it flips back to true
Copy code
apply
Why doesn't it get created?!?
At that point if I press a button (like press it down and don't release it) it will go ahead and do
Copy code
created
changed
changed
Something just feels wrong here
j
I think you want to move apply block after Surface View to AndroidView setup method. Factory only called once upon creation I think. Setup block called each recomposition.
See sample at https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose Argument called update what I referred to as setup.
For callback I also think potentially need rememberupdated and store outside AndroidView to remember it not recreated each time view recomposition or inflates.
c
Interesting point with remember of the callback. I guess I can try that.
j
Its a little complicated how compose evaluates lambda expressions if they refer to stateful compose states. You want updating lambda when that happens but keep lambda itself. Helped me a lot of times but also confusing me. Potentially solves part of your issue. As I dont know rest of code not sure.
c
Yeah. when im back at my desk i will give this a try
j
Also can be bugs under hood. Mixing AndeoidView interop not always play nice, like nested scrolling in Webview. Could be some ui frame updating in SurfaceView behaves different. But I am no expert :) I just avoid AndroidView in compose as much as possible.
c
Yep. I wish I could avoid it here.
v
Hey @Colton Idle, did you ever figure out what is happening here?
c
I filed a bug I believe and I think they said something fixed it. lemme look
my fix was changing the size on the if statement as well. I just added like 2 dp to the size. No one noticed the difference in height, but it did fix the issue.
v
Thanks for the info! I'm running into this same bug 😰
c
oh hot damn. def reply to that same issue tracker. i can try to go back to my code and retry things if it helps.
just out of curiosity. what are you using the surface view for?
im showing a usb camera output in mine. 😅
v
I'll get back to this when I'm working again after the holidays 😄
K 1
The surface is used for media playback, streaming video for example so quite important to be working 😅
It seems like the issue is that the onSurfaceCreated is not called before something else draws to the screen. I tried your minimal reproduction project, but I couldn't reproduce it with that
I also tried making my own minimal reproduction but not reproducable with that either... seems to be multiple conditions to get it to break
But in the place that it currently does break it does every time
Requires a specific api level too
266 Views