Stylianos Gakis
01/09/2022, 4:34 PMval lifecycleOwner = LocalLifecycleOwner.current
var audioPlayer: AudioPlayer? by remember {
mutableStateOf(null)
}
DisposableEffect(audioUrl, lifecycleOwner) {
val localAudioPlayer = AudioPlayer(audioUrl, lifecycleOwner)
audioPlayer = localAudioPlayer
onDispose {
localAudioPlayer.cleanup()
}
}
So using DisposableEffect to make sure to cleanup the AudioPlayer in case any of the keys change and I create a new instance of AudioPlayer so I cleanup the old one, or if it leaves the composition.
This feels a bit hacky however, especially with the initial null state above it, making the code below this awkward too. Is there some better approach I could possibly look into instead?Dominaezzz
01/09/2022, 4:42 PMDominaezzz
01/09/2022, 4:42 PMStylianos Gakis
01/09/2022, 5:01 PMjava.io.Closeable
?Dominaezzz
01/09/2022, 5:02 PMStylianos Gakis
01/09/2022, 5:03 PMStylianos Gakis
01/09/2022, 5:07 PM@Composable
fun <T : Closeable> rememberCloseable(
key1: Any?,
key2: Any?,
calculation: () -> T,
): T {
val wrapper = remember(key1, key2) { Wrapper(calculation()) }
return wrapper.obj
}
Dominaezzz
01/09/2022, 5:08 PMZach Klippenstein (he/him) [MOD]
01/10/2022, 8:39 PMStylianos Gakis
01/10/2022, 10:17 PMZach Klippenstein (he/him) [MOD]
01/10/2022, 10:19 PMStylianos Gakis
01/10/2022, 10:34 PMinitialize
function that I can call later and not during object creation. That could help in this case right?Zach Klippenstein (he/him) [MOD]
01/10/2022, 10:36 PMZach Klippenstein (he/him) [MOD]
01/10/2022, 10:37 PMStylianos Gakis
01/11/2022, 7:18 AMclose
coming from the Closeable
interface. I think I have to do what we said yeah, initialize it later.
Maybe as a
LaunchedEffect(audioPlayer) {
audioPlayer.initialize()
}
But I am not sure if this would behave the same way as you said before, re-trigger multiple times. And if it does, where else would that fit while we’re inside the context of a composable?Zach Klippenstein (he/him) [MOD]
01/11/2022, 3:53 PMZach Klippenstein (he/him) [MOD]
01/11/2022, 3:55 PMinitialize
a suspend function so it can do its own cleanup, and then call it something other than initialize to indicate it's long-running (maybe run
?)
Or change it to an initialize/dispose pair and use DisposableEffect like you had before.Stylianos Gakis
01/11/2022, 4:15 PMclass AudioPlayer(key1: Any?, key2: Any?) {
fun initialize() { TODO() }
fun cleanup() { TODO() }
}
@Composable
fun Something(key1: Any?, key2: Any?) {
val audioPlayer = remember(key1, key2) {
AudioPlayer(key1, key2)
}
DisposableEffect(audioPlayer) {
audioPlayer.initialize()
onDispose {
audioPlayer.cleanup()
}
}
}
2:
class AudioPlayer2(key1: Any?, key2: Any?) {
suspend fun activate() {
initialize()
try {
awaitCancellation() // Is this the best way to do this?
} finally {
cleanup()
}
}
private fun initialize() { TODO() }
private fun cleanup() { TODO() }
}
@Composable
fun Something2(key1: Any?, key2: Any?) {
val audioPlayer = remember(key1, key2) {
AudioPlayer2(key1, key2)
}
LaunchedEffect(audioPlayer) {
audioPlayer.activate()
}
}
3:
class AudioPlayer3(key1: Any?, key2: Any?) : Closeable {
fun initialize() {}
override fun close() {}
}
@Composable
fun Something3(key1: Any?, key2: Any?) {
val lifecycleOwner = LocalLifecycleOwner.current
val audioPlayer = rememberCloseable(key1, key2) {
AudioPlayer3(key1, key2)
}
LaunchedEffect(audioPlayer) {
audioPlayer.initialize()
}
}
Would all be reasonable with their own pro/cons in terms of how easy they are to use on the call site. With 1 being the most explicit on the call site about when we are initializing it and disposing it. 2 probably being the most concise on the call site. 3 introducing the new concept of rememberCloseable which may not be universally understood?
If all those are correct and hide no bugs idk which one to pick tbh. But might be that not all of them behave exactly the same, what do you think?Zach Klippenstein (he/him) [MOD]
01/11/2022, 4:56 PMrememberCloseable
but the first two look good.Dominaezzz
01/11/2022, 5:06 PMStylianos Gakis
01/11/2022, 6:54 PM