I want to add a Repeat button. Is it possible to r...
# compose
v
I want to add a Repeat button. Is it possible to restart flow like this? It seems to work, but Composable is not updated.
Copy code
val user by viewModel.loadingUser.collectAsState(initial = null)
when {
    user.isSucceeded -> navController.navigate(NavScreen.Home.route)
    user.isError -> ErrorConnect { viewModel.repeat() }
    else -> Splash()
}
k
Is the
when
block in a composable? Also what is
ErrorConnect
? Can you show more of your code.
v
@Composable
loadingUser
It works, but it seems to me that this is not the right way.
p
Why would you annotate a launching function as worker thread?
1
k
There are multiple things 1. Your
repeat()
does not restart the
.collectAsState()
, instead it just starts collecting the flow independently. Is there a way you can get a flow of the latest
user
value from your
ServiceUser
? 2. Code with side effects (such as
NavController.navigate()
) should not be in composable function (see [1]). In your case you can simply switch between what is being displayed by the value of user
Copy code
val user by viewModel.loadingUser.collectAsState(null)
when {
    user.isSuceeded -> TabsHome(...)
    user.isError -> Error()
    null -> Splash()
}
Although I don't see the case here, if you really need to have the different screens as destinations , use
LaunchedEffect()
Copy code
val user by viewModel.loadingUser.collectAsState(null)
LaunchedEffect(user) {
  ... navigate depending on the value of user ...
}
[1] https://developer.android.com/jetpack/compose/side-effects
🙏 1
v
1. This looks like right. It works.
p
Hmm. Without a buffer capacity, wouldn't that tryEmit only work when there is a collector?
v
Is emit better? I'm probably missing something. I did by analogy with LiveData.
k
Since
RepositoryUser.loadingUser()
finishes, I would probably do this
Copy code
private val _loadingUser: MutableStateFlow<ResponseResult<ModelUser>> = MutableStateFlow(null)
val loadingUser = _loadingUser.asStateFlow()

init {
    reload()
}

fun reload() {
    repository.loadingUser()
        .onEach { loadingUser.value = it }
        .launchIn(viewModelScope)
}
Ultimately, if
ServiceUser.getUser()
cannot be made reactive, I wouldn't bother to wrap it in a flow as you did in
loadingUser()
. If I see a
Flow
, I assume it to always provides me with the latest value
v
I don't think MutableStateFlow needs to be made public
k
just fixed it
🙏 1
1
v
@knthmn it's working. THX
@Paul Woitaschek
Why would you annotate a launching function as worker thread?
https://developer.android.com/studio/write/annotations#thread-annotations
p
That makes no sense to me
You want to annotate functions that block as WorkerThread
1
Well actually in coroutines world I would just make blocking functions suspending and wrap it in a withContext(Io)
👍 1