I have some questions. - Why we need a list of error messages? - In 9:13 if we'll update the _uiState, our view will observe and update the view again. So what if we have > 1 error messages inside the errorMessages list? Will it show the next error?
Seems very complicated to do something that should be very simple. This is not an accessible framework. The existence of a SnackbarHostState suggests we also need one for AlertDialog or am I mistaken as I can't see one provided?
If the VM emits HomeUiState will that not recompose the whole Composable? Why wouldn't it be better to split up UiState to multiple flows so the individual data is updating to the corresponding composable?
Thanks for the video! I think there is an error on the slide starting at minute 2:02? I think the composable in HomeRoute should be HomeScreenWithList, not HomeRoute again?
`LaunchedEffect(errorMessageText, retryMessageText, scaffoldState)` in 7:29 looks like magic, could you please elaborate how it ensures "exactly once" semantics? Without a very good documentation we might get a lot of subtle bugs around it. BTW, this particular case with snackbars may be handled much easier by hoisting `snackBarHostState` to ViewModel. It's clever enough to start dismiss timer only when the app is in the foreground and restart it on configuration changes. Works like a charm. :)
We simplified the actual code that can be found here: github.com/android/compose-samples/blob/main/JetNews/app/src/main/java/com/example/jetnews/ui/home/HomeViewModel.kt#L43
Why not use a Channel to emit one-shot events from the ViewModel to the View? You can collect it as a flow and avoid the whole part about telling the VM that the View has triggered the event (which seems redundant). The only downside I can think of is that it only allows for one subscriber at the time which can make it tricky if you have multiple sources that need to capture the view event.
Channels no longer guarantees the delivery of the event from coroutines 1.4 (see github.com/Kotlin/kotlinx.coroutines/issues/2886), that's why it's something we cannot recommend. More info here: developer.android.com/jetpack/guide/ui-layer/events#other-use-cases
@@vengateshm2122 The problem with SharedFlow is that when there are no subscribers any events sent are dropped and therefore lost, which means that if your UI is not subscribed to the flow (configuration changes, app backgrounded and the UI observing the flow using the new lifecycle APIs...) the events will get lost. That makes them not reliable to send events to the UI. Channels on the other hand deliver the events only once and if they have no subscribers they keep the event in memory until a new subscriber appears and delivers the event to it only once (which makes them perfect for UI events from VM to View in my opinion).
Channels are often not convenient with Compose, because any recomposition will make that one-shot side effect disappear, since it's consumed only once. This also makes impossible to, for example, show a dialog, rotate the screen and keep the dialog on the screen. You need to persist the dialog state for that, and with Channel the dialog will disappear after rotation.
@@manuelvicnt Thank you for pointing to the Github issue. What are the cases where an event could be lost when using a Channel? For what I can tell from your comments in Github, is that when the UI receives the event but the view gets recreated right before handling/processing it? (so the Channel has actually delivered the event but because the view recreated the event is effectively lost and you have no info if the event was executed or not from the view perspective?). I can also see you mentioning the filtering operator which makes sense because the Channel would have effectively delivered the event but the view would have filtered it out. However I guess that as long as you remember that and you don't filter out events that you don't want to lose you should be safe. Any other examples you can think of?
Could I use rememberCoroutineScope() instead of LaunchedEffect in the scenario proposed in the video 7:26? What differences are there between these two APIs in this case?
RememberCoroutineScope should now be used directly in composable function, as we have no control over how many times the state will re-compose, but launched effect takes care of it, the block inside the launched effect will only get triggered when its keys changes or the logic inside block gets triggered. So Launched effect is better option than RememberCoroutineScope
all these lines of codes to filter string resources in order to send notifications and snack messages. How about a switch structure in good ole Java that checks for the string resource and then easily determine whether a notification or snack message is needed.
I'd prefer to emit ui state with 3 different flows instead of single 'uiState'. So when, for ex., 'loading' is changed, I emit the new value for only 'loading'. The same for 'errorMessages' and 'searchInput'. I understand that there may be case when 2 or more properties should be updated at once. In this case I agree that it is better to emit state via single 'uiState' property. Is there any other pros for single 'uiState' flow?
Exposing multiple streams of data is ok as long as they provide unrelated data to the UI, otherwise, you could create inconsistent UIs if those streams are out of sync. More info here: developer.android.com/jetpack/guide/data-layer#additional-considerations
@@manuelvicnt Thanks for sharing. I discussed it with my colleague about it. We came to that using multiple flows increases the possibility of errors as you've mentioned. And it requires more attention. So it is better to use single state flow.
How hard is for Google to use native speakers when making these videos? The presenter does not need to be a Software engineer (they use scripts anyway), the main purpose is to understand what you are trying to explain to us. Why add another layer of complexity when we have to struggle to understand what words exactly he is saying? P.S. The content is good! :)
In my code, I use a LaunchedEffect(vm) (where vm is the viewmodel) to observe a mutableSharedFlow which contains sealed classes that describe events the ViewModel wants the UI to take ShowDialog,NavigateToScreen, ShowSnackbar etc. and since it is a mutableSharedFlow , as soon as it is collected it is removed from the flow and it won't be executed again is that better or worse than having the ui events as shown above and sending back to the viewmodel events such as DialogShown, NavigatedToScreen or SnackbarShown?
With SharedFlow you need to be careful as events can be "emitted" without the consumer being listening, if that happens, the event is lost. The UI doesn't always need to notify the ViewModel that the event was handled, that's only needed when another state change happens on that screen (in this case, the message being displayed is another state change). Here in the docs, we talk about different use cases and APIs, and why we recommend this approach: developer.android.com/jetpack/guide/ui-layer/events#other-use-cases
@@manuelvicnt You are right about shared flow, I used to use SingleLiveEvent for such calls , and I've been trying to make a SingleMutableStateFlow that will behave the same for UI calls. Thank you for the link I will read it, but from the experience I got using compose with MVI in the project I am working currently, I always need to notify the VM that the event was handled (at least before I switched to shared flow) otherwise events would trigger again and again, because the state would still have in it that , for example, the user wants to navigate to the login screen, so if another part of the state changes , it will trigger the event again if I don't clear it. Am I missing something?
I have some questions.
- Why we need a list of error messages?
- In 9:13 if we'll update the _uiState, our view will observe and update the view again. So what if we have > 1 error messages inside the errorMessages list? Will it show the next error?
Seems very complicated to do something that should be very simple. This is not an accessible framework. The existence of a SnackbarHostState suggests we also need one for AlertDialog or am I mistaken as I can't see one provided?
Kotlin complicated everything! And this UI layer as well.. haha
If the VM emits HomeUiState will that not recompose the whole Composable? Why wouldn't it be better to split up UiState to multiple flows so the individual data is updating to the corresponding composable?
I don't understand why scaffoldState is used as a key to the LaunchedEffect. Can you explain that?
Thanks for the video! I think there is an error on the slide starting at minute 2:02? I think the composable in HomeRoute should be HomeScreenWithList, not HomeRoute again?
`LaunchedEffect(errorMessageText, retryMessageText, scaffoldState)` in 7:29 looks like magic, could you please elaborate how it ensures "exactly once" semantics? Without a very good documentation we might get a lot of subtle bugs around it.
BTW, this particular case with snackbars may be handled much easier by hoisting `snackBarHostState` to ViewModel. It's clever enough to start dismiss timer only when the app is in the foreground and restart it on configuration changes. Works like a charm. :)
Thanks a lot for your lessons!😇
It is certainly our pleasure! You can also find additional information by visiting our guide to app architecture at goo.gle/Architecture 🌠
Hello everyone, I have a problem, WebView does not display png images, how can I fix it? I would be very grateful for your help
Nice video. Thanks.
Is it possible to have sources of this exemple in a github repo for example?
Sure! You can find them in the Compose Jetnews sample: goo.gle/compose-samples-jetnews
@@manuelvicnt thanks !
I feel like you guys can significantly reduce the boiler plate here, it quickly grows out of control
HomeUiState is a sealed class, but I didn't see child classes. Having child classes doesn't mean that you need an additional when block in the view?
We simplified the actual code that can be found here: github.com/android/compose-samples/blob/main/JetNews/app/src/main/java/com/example/jetnews/ui/home/HomeViewModel.kt#L43
R.string.load_error (need context) in viewmodel. How you do that without context ? please reply my message
I have a question ... where can we buy those cute Android bots that are on the shelves?
Is that Google think compose can replace view now?
Why not use a Channel to emit one-shot events from the ViewModel to the View? You can collect it as a flow and avoid the whole part about telling the VM that the View has triggered the event (which seems redundant).
The only downside I can think of is that it only allows for one subscriber at the time which can make it tricky if you have multiple sources that need to capture the view event.
SharedFlow can also be used for one time event
Channels no longer guarantees the delivery of the event from coroutines 1.4 (see github.com/Kotlin/kotlinx.coroutines/issues/2886), that's why it's something we cannot recommend. More info here: developer.android.com/jetpack/guide/ui-layer/events#other-use-cases
@@vengateshm2122 The problem with SharedFlow is that when there are no subscribers any events sent are dropped and therefore lost, which means that if your UI is not subscribed to the flow (configuration changes, app backgrounded and the UI observing the flow using the new lifecycle APIs...) the events will get lost.
That makes them not reliable to send events to the UI. Channels on the other hand deliver the events only once and if they have no subscribers they keep the event in memory until a new subscriber appears and delivers the event to it only once (which makes them perfect for UI events from VM to View in my opinion).
Channels are often not convenient with Compose, because any recomposition will make that one-shot side effect disappear, since it's consumed only once. This also makes impossible to, for example, show a dialog, rotate the screen and keep the dialog on the screen. You need to persist the dialog state for that, and with Channel the dialog will disappear after rotation.
@@manuelvicnt Thank you for pointing to the Github issue. What are the cases where an event could be lost when using a Channel?
For what I can tell from your comments in Github, is that when the UI receives the event but the view gets recreated right before handling/processing it? (so the Channel has actually delivered the event but because the view recreated the event is effectively lost and you have no info if the event was executed or not from the view perspective?).
I can also see you mentioning the filtering operator which makes sense because the Channel would have effectively delivered the event but the view would have filtered it out. However I guess that as long as you remember that and you don't filter out events that you don't want to lose you should be safe.
Any other examples you can think of?
Instead of errorMesseges[0] you can use errorMesseges.first()
Could I use rememberCoroutineScope() instead of LaunchedEffect in the scenario proposed in the video 7:26? What differences are there between these two APIs in this case?
RememberCoroutineScope should now be used directly in composable function, as we have no control over how many times the state will re-compose, but launched effect takes care of it, the block inside the launched effect will only get triggered when its keys changes or the logic inside block gets triggered.
So Launched effect is better option than RememberCoroutineScope
Thanks
all these lines of codes to filter string resources in order to send notifications and snack messages. How about a switch structure in good ole Java that checks for the string resource and then easily determine whether a notification or snack message is needed.
Love MAD Skills!!
where is the model?
I'd prefer to emit ui state with 3 different flows instead of single 'uiState'. So when, for ex., 'loading' is changed, I emit the new value for only 'loading'. The same for 'errorMessages' and 'searchInput'.
I understand that there may be case when 2 or more properties should be updated at once. In this case I agree that it is better to emit state via single 'uiState' property. Is there any other pros for single 'uiState' flow?
Exposing multiple streams of data is ok as long as they provide unrelated data to the UI, otherwise, you could create inconsistent UIs if those streams are out of sync. More info here: developer.android.com/jetpack/guide/data-layer#additional-considerations
@@manuelvicnt Thanks for sharing. I discussed it with my colleague about it.
We came to that using multiple flows increases the possibility of errors as you've mentioned. And it requires more attention. So it is better to use single state flow.
compose and kotlin... Gotta make it a point to learn these soon. Problem is my company is very Java centric so no time to do it.
How hard is for Google to use native speakers when making these videos? The presenter does not need to be a Software engineer (they use scripts anyway), the main purpose is to understand what you are trying to explain to us. Why add another layer of complexity when we have to struggle to understand what words exactly he is saying?
P.S. The content is good! :)
Большое спасибо автору, классное видео)
Спасибо автору,классно видео
In my code, I use a LaunchedEffect(vm) (where vm is the viewmodel) to observe a mutableSharedFlow which contains sealed classes that describe events the ViewModel wants the UI to take ShowDialog,NavigateToScreen, ShowSnackbar etc. and since it is a mutableSharedFlow , as soon as it is collected it is removed from the flow and it won't be executed again
is that better or worse than having the ui events as shown above and sending back to the viewmodel events such as DialogShown, NavigatedToScreen or SnackbarShown?
It does seem like an unneeded step to need the ui to notify the vm to remove the state.
With SharedFlow you need to be careful as events can be "emitted" without the consumer being listening, if that happens, the event is lost. The UI doesn't always need to notify the ViewModel that the event was handled, that's only needed when another state change happens on that screen (in this case, the message being displayed is another state change). Here in the docs, we talk about different use cases and APIs, and why we recommend this approach: developer.android.com/jetpack/guide/ui-layer/events#other-use-cases
@@manuelvicnt You are right about shared flow, I used to use SingleLiveEvent for such calls , and I've been trying to make a SingleMutableStateFlow that will behave the same for UI calls.
Thank you for the link I will read it, but from the experience I got using compose with MVI in the project I am working currently, I always need to notify the VM that the event was handled (at least before I switched to shared flow) otherwise events would trigger again and again, because the state would still have in it that , for example, the user wants to navigate to the login screen, so if another part of the state changes , it will trigger the event again if I don't clear it. Am I missing something?
@@manuelvicnt Thanks, I'll check the link out!
That's ugly and doesn't solve the issue, when event is not UI related.
Hi
Awesome
Thank you, Heshan 😄
How can i get android figure like do you have
I got them from here! www.deadzebra.com/project/android-collectibles/ :D
@@manuelvicnt thanks it's cool =D
hi
No need to have te homeRoute composable
Ok
In my code, ha