https://kotlinlang.org logo
#compose
Title
# compose
f

Felipe Passos

05/31/2021, 11:36 AM
Hello, how do i make this idea work : api.stream is reading a websocket, the idea is to update a variable every time it receives a websocket message.
s

Se7eN

05/31/2021, 11:41 AM
You can use a lambda:
Copy code
suspend fun updateState(api: Api, onRecieve: (String) -> Unit) {
    val notify =  Channel<String>()
    api.stream(notify)
    while(true) {
        onRecieve(notify.receive())
    }
}  

@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun SomeComposable(api: Api, locationViewModel: LocationViewModel = viewModel()) {
    var state by remember { mutableStateOf("") }
    val composableScope = rememberCoroutineScope()
    composableScope.launch {
        updateState(api, onRecieve = { state = it })
    }
}
f

Felipe Passos

05/31/2021, 11:45 AM
This makes the api.stream goes on some loop and connect multiple times instead of one time and just reading
s

Se7eN

05/31/2021, 11:46 AM
Oh yeah you need
LaunchedEffect
f

Felipe Passos

05/31/2021, 11:47 AM
What is this ?
f

Felipe Passos

05/31/2021, 11:49 AM
What do i use as a key?
Oh, get it
s

Se7eN

05/31/2021, 11:50 AM
I guess you can use your api as the key since it will relaunch when your api changes
Also, shouldn't the
updateState
be in your view model?
f

Felipe Passos

05/31/2021, 11:52 AM
Any idea why it prints "" then the real state value ?
s

Se7eN

05/31/2021, 11:53 AM
Because the initial value of your state is an empty string
f

Felipe Passos

05/31/2021, 11:54 AM
Any way to the variable only holds the newer value ?
I'm using the view model to store some coordinates that changes when the user click on a map
s

Se7eN

05/31/2021, 11:56 AM
You can make the state null initially or maybe use a flow
You can make another view model for your api stuff if you don't want it in the location view model
f

Felipe Passos

05/31/2021, 12:05 PM
So a viewModel is better than a simple remember in this case?
s

Se7eN

05/31/2021, 12:15 PM
From what I'm seeing, yes. It's always better to keep the UI separate
d

Dominaezzz

05/31/2021, 12:16 PM
Should probably be
fun updateState(api: Api): Flow<String>
that returns a
channelFlow { .... }
. Then you can use
collectAsState()
.
f

Felipe Passos

05/31/2021, 12:18 PM
What would be a snippet of this ? i never used a channelFlow before
d

Dominaezzz

05/31/2021, 12:25 PM
Copy code
fun updateState(api: Api): Flow<String> {
    return channelFlow<String> {
        api.stream(this)
        awaitClose { /* do closing things if needed */ }
    }
}
Copy code
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun SomeComposable(api: Api, locationViewModel: LocationViewModel = viewModel()) {
    val state by remember(api) { updateState(api) }.collectAsState("")
    // do stuff with state
}
f

Felipe Passos

05/31/2021, 12:29 PM
I saw here that it is a experimental api, is this safe to use ?
d

Dominaezzz

05/31/2021, 12:30 PM
It was stabilised in the latest release so don't worry about it.
f

Felipe Passos

05/31/2021, 12:55 PM
Ok, thank you all !
👍 1
3 Views