Raid Xu
01/14/2025, 3:48 AM@Composable
function will cause memory leak?
I thought a @Composable function is stateless but looking at ComposableLambdaImpl there is a RecomposeScope in it.
Does this mean we should not keep a @Composable
longer than the scope it is in?
Is there a workaround to keep a long live @Composable
without having a leak?
BTW by @Composable
function I mean creating properties like val foo = @Composable { ... }
shikasd
01/14/2025, 1:01 PMRaid Xu
01/14/2025, 2:11 PMshikasd
01/14/2025, 2:21 PMMatthew David
01/14/2025, 2:47 PMRaid Xu
01/14/2025, 3:38 PMshikasd
01/14/2025, 3:48 PMRaid Xu
01/14/2025, 4:49 PMshikasd
01/14/2025, 5:19 PMRaid Xu
01/22/2025, 11:04 AMclass MainActivity : ComponentActivity() {
private val vm: ComposableLambdaViewModel by viewModels<ComposableLambdaViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column {
if (vm.invoked == 0) {
vm.composable.invoke(this@MainActivity)
}
Greeting("Compose")
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
class ComposableLambdaViewModel : ViewModel() {
val composable =
@Composable { _: Any? ->
Text("Hello from composable lambda")
DisposableEffect(Unit) {
invoked += 1
onDispose { }
}
}
var invoked = 0
}
If you launch this Activity then rotate, the Activity will be leaked. There are few key requirements for the repro:
• Keeping the composable lambda property in view model
• Pass a short-live object when invoking composable (in my sample, the activity itself)
• After rotate, don't invoke the composable again
It seems the RecomposeScope keeps a reference to parameters that passed to composable lambda (for computing changes?).
I guess we can't really avoid passing short-live objects into composables, do you have any suggestion on how to workaround this?shikasd
01/22/2025, 11:17 AM