I like these type of videos which does not directly teach a new concept but rather opens a discussion on a special topic this made me understand the topic better in deep, thanks for this, and hope for more videos of this type !
Thank you so much for your videos. I’m writing a diploma work in my university using Android development, I have never worked with mobile applications and I’m really love clean architecture, so your videos about MVVM, about Jetpack compose, comparison sharedFlow, channels, QR-codes, cameraX, AI and so on are GREAT. So maybe it’s just simple word “thanks” for you, Philipp, but you should know, that this “thanks” for me is COLOSSAL THANKS! I’m from Russia and our developers on RUclips don’t talk about all of this as good as you! So don’t stop making this very useful and meaningful videos, you are great)
We actually have used another workaround for this - the old school Event class with isConsumed property. So the ViewModel sets the state (StateFlow), then the Fragment during consumption first checks if the Event has been consumed already (in which case just ignores it), then if not - does what it needs to do and sets the property isConsumed to true. This combined with some extension functions (like consumeIfHasntBeenAlready and peekContent for testing) makes a flawless job
Great video, thanks! one thing to add for 7:00 channel's default capacity 0 which used in the video and it creates a rendezvous channel. Publisher suspends itself until there is subscriber or subscriber suspends until there is a publisher.
Awesome video, thanks! We use state way for one-time events. To unify the handling of such events we've created a common interface like: interface UiEvent { val data: T val onConsumed: () -> Unit }. Where the `onConsumed` callback is set to the view model's function to set event property in the state to null. With some nice extensions, handling of such events on the UI layer is uniformed and clean.
I agree with you Philipp... When we are using "Channels", the code is simpler to understand, and thinking about junior developers, working with states in this situation can be hard and generate a lot of bugs. This kind of thought about right and wrong depends on the context. Nice video, thank you for sharing your knowledge with us.
I used state to trigger & Observe event in my Jetpack compose project and I can say it was a pain in as*** as most of the time I forgot to reset the state back after it's single use.. So thanks Philipp for having this video on youtube to guide people like us. Thanks a lot...
I dealt with this dilemma for several weeks last year and I'm glad I ultimately stuck with the same solution that you did. If you have a solid understanding of channels and can handle them correctly, there's no need to use state for single events. 👍
Very nice video! I have been battling with how to implement one-time events and ended up following Manuel's advice because I wanted to stay on the safe side. But I agree that it introduces a lot of complexity and one junior developer in my team doesn't really understand it. I myself can forget about resetting the state also. But now I feel more comfortable using channels and think I will switch to that :)
Hey Phillip I subscribed to your channel a while ago because I got really interested in Android content but I stopped watching your videos because they just weren't that great presented compared to reading a blog article etc. Now I just want to give some positive feedback because this video is very good, referring to the blog article, preparing an example that demonstrates the different cases and keeping it all readable was very helpful. Your insights and POV are very valuable, thank you for the effort and I'll definitely tune in more often 👍
thanks Philipp for the deep dive on the topic! i'm working on a greenfield project with compose and i was really not sure how to best handle this kind of viewmodel driven navigation scenario. i fully understand the options now!
I saw the use of channels first in your form validation video and it blown my mind, because first I was using events then unknowingly has the same implementation as manuel, but I didn't like it for the same reason that I need to reset it everything, for me it looked dirty. So when I saw the channels in your form validation video, I replaced it and works and look what I want it to be!
oh shut up junior ! stop encouraging antipatterns. There is a proper way to do something, thats why we have different things like stateflow or sharedflow.
The only issue is that rotation isn't the only reason to lose event. If you consider that ViewModel could be recreated too state will be on top of the solutions list.
@@PhilippLackner UI also wont exist. Example is when the user start operation, switches to another app and Android decides to kill your app. When user get back, ViewModel needs to be restored and show correct UI and having state is more suitable for that.
First! Finally this topic! Indeed, resetting state which is being suggested by many can cause more bug when someone forgets it instead of sticking to use channel. Thanks a lot
channel are really bad for that, the second your app will be killed by the system you will have an inconsistent state between your state and channel, and that's way worse than "someone forgetting" Design errors are worse than dev errors
Fair enough, actually that is what we are doing currently. However if this is the case then all we need here is to use StateFlow directly so no need to convert Channel to state. Unfortunately manually resetting each state is making it hard to maintain and it adds more complexity to read the system flow. So this approach is where we are heading.
Your videos have been incredibly helpful, and I really appreciate you sharing your knowledge. I recently tried to put your Jetpack Compose tutorial into practice while building an app, but I'm having trouble with the login/register navigation and home nested navigation. Specifically, I'm unsure how to manage the scaffold for the login and register screens, and I'm also struggling to customize the FAB for each screen in the home nested navigation. Any guidance you could provide would be greatly appreciated.
why does android not provide a simple and optimal way to develop apps, instead of focusing on core development of what features our might need, developers have to worry about what to use for development, there are so many permissions to handle that it has become crazy, then with compose state and viewmodel, in viewmodel satetfllow, sharedflow, and the list goes on, and the pace at which these changes come makes all the code developed earlier redundant
I agree, but I think it's also incredibly easy to say that and hard to do. Making everything safe for users, easy for developers, easy to use for users, run as fast as possible is very complex and a lot of interests clash together. If developers would have a much more limited toolkit which is simpler to use, they'd again complain why they don't have fine grained control. It's just hard to please everyone to the fullest degree.
You dont need to use all these tools. In fact they are pretty useless if you know what are you doing. Most of these things can be replaced by common and 'old' patterns, which didnt have these problems btw
@@Naxomiun using old tools has the advantage of their reliability but there is always a risk of google deprecating them and bringing out half baked or totally different tools, the way SAF(Storage Access Framework) was handled then the epic moment when deprecations were deprecated and then brought back, now in compose handling a simple variable or an UI state is just a joke, compose state, view model, they could have just brought one viewmodel api and managed the one time events more effectively, some thing which has to baked in the OS itself is left to the developers, like handling denial of permissions with no Propper out of the box solution where developers have to provide their own logic, instead on working on a new feature for their app , imagine developing an app requiring camera from a service using notification where images and video permission are to be handled for api 32 and lower, api 33 and then api 34 and higher. wonder if the various teams developing different apis within google even communicate with each other where different "features" end up being a problem for developers
You will always be able to use bare threads instead of coroutines, service scoped classes instead of viewmodels, callbacks instead of flows or hand dependency injection instead of Hilt. Theres no way no one could ever deprecate those as they are part of the language. In fact, the possibilities of viewmodels/livedata/etc being deprecated are really high if you know about google historic changes in its APIs.
Thanks for a video on a really interesting topic but I have one question about LaunchedEffect. I have seen in many examples that we have to pass the lifecycle as a key to close the LaunchedEffect if the owner of the lifecycle has changed. But do we really need to pass it as a key? Because according to the documentation the LaunchedEffect will be closed and restarted if one of the keys changes OR the LaunchedEffect leaves the composition. So in general we will only close and restart this effect when the activity has recreated itself (which means that the LaunchedEffect will leave composition even without lifecycle as a key) or I don't understand other cases where the lifecycleOwner is changed Thanks in advance to everyone for any clarification on this question! :)
All this sounds very nice, but how these constructions will behave when we set "Don't keep activities" to ON in Developer options, which will make activity to be recreated every time when we bring test app from bg to fg. This will illustrate how the app will behave after the device goes to "doze" mode.
For somebody who has always used a state-solution, anything else seems odd. Of course you need to handle state reset because it is a state. You can’t get around it no matter what you do. You also need to think about it in the other solutions.
Regarding the article solution, if we are sending events (by updating the compose state object) with a high frequency (milliseconds) doesn't it drop some of them? Since the compose rendering system drops the intermediate states and only considers the last one for the recomposition.
Hey @PhilippLackner , Awesome video, thanks! I have a Qn, WhileSubscribed function takes stopTimeoutMillis. can't we just set stopTimeoutMillis to 5000ms for ex. this will address all the issues when lifecycle/orientation changes happen. it will wait for the collectors to come back, therefore emissions won't get dropped. (StateFlow)
For some reason, the channel option will just be "collectable" once, as well as emitted once. I was hoping I could have 2 different isolated views react to this channel through the viewModel, but only the first view that collects the event will get the "message". I am switching back to state, since this is proven solution for precisely this scenario.
Memory-wise, is there any difference, improvement, best practice to pick sharedflow instead of state in a view controller? Are you saying sharedflow will also emit once, but can be heard by several views and not just one?
What's the difference between collecting state with MutableStateFlow and MutableSharedFlow? I usually use MutableStateFlow but I see other people use MutableSharedFlow as well, which one is recommended?
The difference between the two is mainly in a way they behave upon subscribing to them. I think official docs explain it well, you can then decide which behaviour suits your case better 👍
anyone wondering how to provide Dispatchers.Main.immediate with collectAsStateWithLifecycle; this is how val uiState by viewModel.uiState.collectAsStateWithLifecycle(context = Dispatchers.Main.immediate)
I really disliked the ui state thing with cleanup work. I often have to test a screen many times and oops forgot to clear a state and now it's debugging time. I have been using that pattern, but I run into bugs so often that I's annoying. Which is why I got here I guess. Is there really no downside to this approach tho? it seems like everything we do will sacrifice something in order to achieve something else. If it's just some performance then I would happily give it away as most applications I make are not intensive. Having a less buggy approach beats any performance hit IMO (as long as it doesn't renders the app unusable).
What if we have to send multiple events at one (in a list)? I think the third solution with "state" is most suitable. Plus, in some scenarios we have to later consume this event after an action, i.e undo delete action within a snack bar that we have to keep after rotation.
what can you suggest for state inside viewModels. data class or sealed class. consider the case when ui is very complex, data classes become very big and complex with lots of parameters. is it the sign to use sealed class or even decompose it using another viewModel. so may be multiple viewModels for that particular screen.
Nice video, but to be honest I kinda fell over the argument against state being: "You always need to think about resetting the state [...] when I think of a larger team where the might be junior developers as well [...]" and then proceed to add the Dispatcher.Main.immediate which is equally 'not obvious' (or even worse) in my opinion
Yes, I agree that the immediate dispatcher isn't obvious either, but it's a single rule that has to be established in the team ("when observing events, ALWAYS use this ObserveAsEvents function"). Resetting state is not so trivial, since it sometimes need to be reset and sometimes it's fine to leave it (such as when the previous backstack is cleared after navigation). Even though, I knew the mechanism behind resetting state, it happened to me more often than not that I forgot it. Especially, because one-time events on Android are almost always handled with channels/SharedFlows in Android projects, using state is a rather uncommon approach which is why I think this concept would be new to 95%+ of junior devs and would require an additional intro
Phillip, I'm just blown away by the amount of knowledge you have & your ability to deliver that knowledge in such a precise & to-the-point manner that probably a 10 year old can also understand perfectly fine. Superb, thanks a lot, massive respect, unlimited love! 💙💙💙💙💙💙💙💙💙💙💙💙💙💙💙 BTW, just a funny note, at the end of your video, you could have done that counter check on the best-of-3 condition because previously you had to do that two times to validate your point 😅😅😅😅
I've got a notification about the video exactly when I was about to implement a navigation channel! Coincidence? I think NOT! 😂Thank you Philipp for the amazing content, keep up the Great work! 🙌🏼 Here is a quick snippet of the function to observe such events in a lifecycle manner: @Composable fun CollectFlowWithLifecycle( flow: Flow, lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current, onCollect: suspend (T) -> Unit ) = LaunchedEffect(flow, lifecycleOwner.lifecycle) { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { withContext(Dispatchers.Main.immediate) { flow.collect(onCollect) } } }
It's crazy how often your videos come out when I most need them. Thanks!
I like these type of videos which does not directly teach a new concept but rather opens a discussion on a special topic this made me understand the topic better in deep, thanks for this, and hope for more videos of this type !
Thank you so much for your videos. I’m writing a diploma work in my university using Android development, I have never worked with mobile applications and I’m really love clean architecture, so your videos about MVVM, about Jetpack compose, comparison sharedFlow, channels, QR-codes, cameraX, AI and so on are GREAT. So maybe it’s just simple word “thanks” for you, Philipp, but you should know, that this “thanks” for me is COLOSSAL THANKS! I’m from Russia and our developers on RUclips don’t talk about all of this as good as you! So don’t stop making this very useful and meaningful videos, you are great)
Thank you! All the best for your diploma 💪🏻
We actually have used another workaround for this - the old school Event class with isConsumed property. So the ViewModel sets the state (StateFlow), then the Fragment during consumption first checks if the Event has been consumed already (in which case just ignores it), then if not - does what it needs to do and sets the property isConsumed to true. This combined with some extension functions (like consumeIfHasntBeenAlready and peekContent for testing) makes a flawless job
Great video, thanks!
one thing to add for 7:00 channel's default capacity 0 which used in the video and it creates a rendezvous channel. Publisher suspends itself until there is subscriber or subscriber suspends until there is a publisher.
Awesome video, thanks!
We use state way for one-time events. To unify the handling of such events we've created a common interface like:
interface UiEvent {
val data: T
val onConsumed: () -> Unit
}.
Where the `onConsumed` callback is set to the view model's function to set event property in the state to null.
With some nice extensions, handling of such events on the UI layer is uniformed and clean.
That's awesome, thanks for adding 🙌
I like this solution as well, in case I'd have to stick with state
That is also good idea. If the event is not happen continotly like snackbar text or some of notify , MutableState with reset consume also good.
how to use this . any example
I agree with you Philipp... When we are using "Channels", the code is simpler to understand, and thinking about junior developers, working with states in this situation can be hard and generate a lot of bugs. This kind of thought about right and wrong depends on the context.
Nice video, thank you for sharing your knowledge with us.
Crazy to me how hard it is to make junior colleagues understand the difference between state and one-time events
Great content as always 👍
I used state to trigger & Observe event in my Jetpack compose project and I can say it was a pain in as*** as most of the time I forgot to reset the state back after it's single use.. So thanks Philipp for having this video on youtube to guide people like us. Thanks a lot...
Hey Philipp, excellent work! Can you please make an updated tutorial about ktor and Rest API? I would really appreciate that 🙏
I dealt with this dilemma for several weeks last year and I'm glad I ultimately stuck with the same solution that you did. If you have a solid understanding of channels and can handle them correctly, there's no need to use state for single events. 👍
Very nice video! I have been battling with how to implement one-time events and ended up following Manuel's advice because I wanted to stay on the safe side.
But I agree that it introduces a lot of complexity and one junior developer in my team doesn't really understand it. I myself can forget about resetting the state also.
But now I feel more comfortable using channels and think I will switch to that :)
Hey Phillip I subscribed to your channel a while ago because I got really interested in Android content but I stopped watching your videos because they just weren't that great presented compared to reading a blog article etc.
Now I just want to give some positive feedback because this video is very good, referring to the blog article, preparing an example that demonstrates the different cases and keeping it all readable was very helpful.
Your insights and POV are very valuable, thank you for the effort and I'll definitely tune in more often 👍
Perfect!
I was a fan of the sharedFlow school, but you convinced me as usual😂
thanks Philipp for the deep dive on the topic! i'm working on a greenfield project with compose and i was really not sure how to best handle this kind of viewmodel driven navigation scenario. i fully understand the options now!
I don't care what the other dude from Google says for me. philip is always right. We respect u philip
I saw the use of channels first in your form validation video and it blown my mind, because first I was using events then unknowingly has the same implementation as manuel, but I didn't like it for the same reason that I need to reset it everything, for me it looked dirty. So when I saw the channels in your form validation video, I replaced it and works and look what I want it to be!
there is no RIGHT way to do ANY thing in android
yes people just care about funectionality and performance of the app , they dont care for example you used jetpack compose or xml or native drawing
oh shut up junior ! stop encouraging antipatterns. There is a proper way to do something, thats why we have different things like stateflow or sharedflow.
This is a thumbs up video from me. After creating some complex apps I am entirely aligned with your position on this topic! Keep up the good work ;-)
The only issue is that rotation isn't the only reason to lose event. If you consider that ViewModel could be recreated too state will be on top of the solutions list.
In which scenario would the ViewModel be recreated, but not the UI?
@@PhilippLackner UI also wont exist. Example is when the user start operation, switches to another app and Android decides to kill your app. When user get back, ViewModel needs to be restored and show correct UI and having state is more suitable for that.
@@SerhiiSolodilov ah now I see what you mean, yes that is a good point
I was waiting for this video for so long. Thank you very much!
First! Finally this topic! Indeed, resetting state which is being suggested by many can cause more bug when someone forgets it instead of sticking to use channel. Thanks a lot
channel are really bad for that, the second your app will be killed by the system you will have an inconsistent state between your state and channel, and that's way worse than "someone forgetting"
Design errors are worse than dev errors
Fair enough, actually that is what we are doing currently. However if this is the case then all we need here is to use StateFlow directly so no need to convert Channel to state. Unfortunately manually resetting each state is making it hard to maintain and it adds more complexity to read the system flow. So this approach is where we are heading.
I loved the video. Would love more of such content. Explaining differences of approaches
Excellent video, you explained every scenario flawlessly 👌
Very nice, it's amazing, good luck Phillip!
Today only I was working on same functionality, really thanks its really helped
This is very very very important and powerfull tip!!!!!! Thanks Philipp!!!!
Super useful breakdown of a controversial and misunderstood factor of Andriod and pure compose apps
Sounds like we are still in process of finding best mechanism of doing one shot event from viewModel to UI
Brilliant video on a topic full of nuances, nice one :)
Your videos have been incredibly helpful, and I really appreciate you sharing your knowledge. I recently tried to put your Jetpack Compose tutorial into practice while building an app, but I'm having trouble with the login/register navigation and home nested navigation. Specifically, I'm unsure how to manage the scaffold for the login and register screens, and I'm also struggling to customize the FAB for each screen in the home nested navigation. Any guidance you could provide would be greatly appreciated.
It is amazing. I always learn new thing when watching your video. Thanks
wisdom!!! thanks always Philipp
why does android not provide a simple and optimal way to develop apps, instead of focusing on core development of what features our might need, developers have to worry about what to use for development, there are so many permissions to handle that it has become crazy, then with compose state and viewmodel, in viewmodel satetfllow, sharedflow, and the list goes on, and the pace at which these changes come makes all the code developed earlier redundant
I agree, but I think it's also incredibly easy to say that and hard to do. Making everything safe for users, easy for developers, easy to use for users, run as fast as possible is very complex and a lot of interests clash together.
If developers would have a much more limited toolkit which is simpler to use, they'd again complain why they don't have fine grained control. It's just hard to please everyone to the fullest degree.
You dont need to use all these tools. In fact they are pretty useless if you know what are you doing. Most of these things can be replaced by common and 'old' patterns, which didnt have these problems btw
@@Naxomiun using old tools has the advantage of their reliability but there is always a risk of google deprecating them and bringing out half baked or totally different tools, the way SAF(Storage Access Framework) was handled then the epic moment when deprecations were deprecated and then brought back, now in compose handling a simple variable or an UI state is just a joke, compose state, view model, they could have just brought one viewmodel api and managed the one time events more effectively, some thing which has to baked in the OS itself is left to the developers, like handling denial of permissions with no Propper out of the box solution where developers have to provide their own logic, instead on working on a new feature for their app , imagine developing an app requiring camera from a service using notification where images and video permission are to be handled for api 32 and lower, api 33 and then api 34 and higher. wonder if the various teams developing different apis within google even communicate with each other where different "features" end up being a problem for developers
You will always be able to use bare threads instead of coroutines, service scoped classes instead of viewmodels, callbacks instead of flows or hand dependency injection instead of Hilt. Theres no way no one could ever deprecate those as they are part of the language. In fact, the possibilities of viewmodels/livedata/etc being deprecated are really high if you know about google historic changes in its APIs.
Thank you it will helpful absolutely great value to your videos and sharing your experiences with us ❤❤❤❤
great video! Events look like the best option. thanks
Thanks for a video on a really interesting topic but I have one question about LaunchedEffect. I have seen in many examples that we have to pass the lifecycle as a key to close the LaunchedEffect if the owner of the lifecycle has changed. But do we really need to pass it as a key? Because according to the documentation the LaunchedEffect will be closed and restarted if one of the keys changes OR the LaunchedEffect leaves the composition. So in general we will only close and restart this effect when the activity has recreated itself (which means that the LaunchedEffect will leave composition even without lifecycle as a key) or I don't understand other cases where the lifecycleOwner is changed
Thanks in advance to everyone for any clarification on this question! :)
Thanks you shared you thoughts about that . Well-explained👍
Would be nice to hear Manuel Vivo response too 🙂
All this sounds very nice, but how these constructions will behave when we set "Don't keep activities" to ON in Developer options, which will make activity to be recreated every time when we bring test app from bg to fg. This will illustrate how the app will behave after the device goes to "doze" mode.
For somebody who has always used a state-solution, anything else seems odd. Of course you need to handle state reset because it is a state. You can’t get around it no matter what you do. You also need to think about it in the other solutions.
Very well explained Phillip
Great video. Thanks for helping again
I definitely prefer a State to use
Thanks! Now I do understand very well .
Regarding the article solution, if we are sending events (by updating the compose state object) with a high frequency (milliseconds) doesn't it drop some of them? Since the compose rendering system drops the intermediate states and only considers the last one for the recomposition.
Great video! How does SingleLiveData from LiveData lib compare to these solutions using Flow/State?
What about keeping a list of ui events in the state object and update the list when the events are processed ?
Hey @PhilippLackner , Awesome video, thanks! I have a Qn, WhileSubscribed function takes stopTimeoutMillis. can't we just set stopTimeoutMillis to 5000ms for ex. this will address all the issues when lifecycle/orientation changes happen. it will wait for the collectors to come back, therefore emissions won't get dropped. (StateFlow)
Wow, i have been wait too long for video like this. Thankssssss
Can you skip events when you use sharedflow with repeat=1? If you are using it for events, I think this is the easiest solution.
replay = 1 is equivalent of StateFlow :) You will be able to go back then.
For some reason, the channel option will just be "collectable" once, as well as emitted once. I was hoping I could have 2 different isolated views react to this channel through the viewModel, but only the first view that collects the event will get the "message". I am switching back to state, since this is proven solution for precisely this scenario.
What you're looking for is a sharedflow as the name says :)
Memory-wise, is there any difference, improvement, best practice to pick sharedflow instead of state in a view controller? Are you saying sharedflow will also emit once, but can be heard by several views and not just one?
@@TheRcfrias correct, it's like a channel that allows multiple subscribers
its be great if you create a app like music player or chat app and do your best approaches for each senario
What's the difference between collecting state with MutableStateFlow and MutableSharedFlow? I usually use MutableStateFlow but I see other people use MutableSharedFlow as well, which one is recommended?
SharedFlow is NOT state, it doesn't cache anything by default. As the name says, only use StateFlow for state
The difference between the two is mainly in a way they behave upon subscribing to them. I think official docs explain it well, you can then decide which behaviour suits your case better 👍
필립 센세 항상 감사합니다
What about collectAsStateWithLifecycle ? . We can't provide the dispatcher.Main.immediate there can we ?
anyone wondering how to provide Dispatchers.Main.immediate with collectAsStateWithLifecycle; this is how
val uiState by viewModel.uiState.collectAsStateWithLifecycle(context = Dispatchers.Main.immediate)
Would you talk about the new compose Multiplatform wizard ?
I really disliked the ui state thing with cleanup work. I often have to test a screen many times and oops forgot to clear a state and now it's debugging time. I have been using that pattern, but I run into bugs so often that I's annoying. Which is why I got here I guess.
Is there really no downside to this approach tho? it seems like everything we do will sacrifice something in order to achieve something else. If it's just some performance then I would happily give it away as most applications I make are not intensive. Having a less buggy approach beats any performance hit IMO (as long as it doesn't renders the app unusable).
What if we have to send multiple events at one (in a list)? I think the third solution with "state" is most suitable. Plus, in some scenarios we have to later consume this event after an action, i.e undo delete action within a snack bar that we have to keep after rotation.
Hi Phlipp. Thanks for this nice tutorial. How to use observeAsEvent function for our all composables?
this was insightful
what can you suggest for state inside viewModels. data class or sealed class. consider the case when ui is very complex, data classes become very big and complex with lots of parameters. is it the sign to use sealed class or even decompose it using another viewModel. so may be multiple viewModels for that particular screen.
Nice video, but to be honest I kinda fell over the argument against state being: "You always need to think about resetting the state [...] when I think of a larger team where the might be junior developers as well [...]" and then proceed to add the Dispatcher.Main.immediate which is equally 'not obvious' (or even worse) in my opinion
Yes, I agree that the immediate dispatcher isn't obvious either, but it's a single rule that has to be established in the team ("when observing events, ALWAYS use this ObserveAsEvents function").
Resetting state is not so trivial, since it sometimes need to be reset and sometimes it's fine to leave it (such as when the previous backstack is cleared after navigation). Even though, I knew the mechanism behind resetting state, it happened to me more often than not that I forgot it. Especially, because one-time events on Android are almost always handled with channels/SharedFlows in Android projects, using state is a rather uncommon approach which is why I think this concept would be new to 95%+ of junior devs and would require an additional intro
Great videoo, thanks 👍
But the Channel's buffer by default is 0...
Great video
Nice topic bro
cmd + f, my friend. ;)
how about use StateFlow with Event class?
if Mutable StateFlow and live data use so problem
You just need helper container with nullable field
thank youuuuuuuuuuuuuuu
Phillip, I'm just blown away by the amount of knowledge you have & your ability to deliver that knowledge in such a precise & to-the-point manner that probably a 10 year old can also understand perfectly fine.
Superb, thanks a lot, massive respect, unlimited love! 💙💙💙💙💙💙💙💙💙💙💙💙💙💙💙
BTW, just a funny note, at the end of your video, you could have done that counter check on the best-of-3 condition because previously you had to do that two times to validate your point 😅😅😅😅
If using presenter to update the ui?
COMpose
Incredible.Wonderful.Exceptional.
Good morning, do you have a video teaching how to mask input? I didn't find any tutorial teaching how to mask phone number, or even currency
:v i always use the third way
Excellent video. But isn't a coroutine context in viewmodels and in views already Dispatchers.Main.Immediate? I do not understand how this hack works.
I've got a notification about the video exactly when I was about to implement a navigation channel!
Coincidence? I think NOT! 😂Thank you Philipp for the amazing content, keep up the Great work! 🙌🏼
Here is a quick snippet of the function to observe such events in a lifecycle manner:
@Composable
fun CollectFlowWithLifecycle(
flow: Flow,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onCollect: suspend (T) -> Unit
) = LaunchedEffect(flow, lifecycleOwner.lifecycle) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
withContext(Dispatchers.Main.immediate) {
flow.collect(onCollect)
}
}
}