Should You Use Compose State or StateFlow in Your ViewModels?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys and welcome back to a new video in this video I will answer a common question I get and that is let's say you work on a project that is purely written in Jetpack compose and you're obviously using view models which we mostly do with Android projects then what should you actually use in your video model for your UI States should you use compose day directly or should you use something else like live data or state flow in this video I will talk about the differences and advantages and disadvantages of each approach and then give you a very very clear recommendation so the simple sample I want to build here is just a little app where we can click on the background and we change its color to a randomized randomly generated color and I want to show you that with both approaches so on the one hand having a stay flow and on the other hand having compose State directly here now of your model so first of all we have a private Val color forward oh yeah color State flow that's a mutable State flow where we simply have an initial color let's set it to White initially I'll just save the integer here and we can then convert it to compose color on our UI level layer and we also want to have a public immutable version of that which is color as state flow so that's just a normal approach we we use when we use State flow so that the view model can change the mutable version of that but the UI actually only gets the immutable version since the UI shouldn't actually change the value of that directly the compose version of that would be having a variable let's call that compost color instead and that would be by mutable State off and in here we also assign a default color which I think should be like this yes let's import that make it a private set so we achieve the same thing that we that only the viewmodel can actually change this compose color here and then let's say we write a function generate new color and in that function we actually want to first of all generate a new color which is random Dot next long and we want to cap that at the maximum at the highest color value we can actually achieve which is wide again so we just yeah randomly generate the color here and we then assign that on the one hand to our state flow using color dot value and on the other hand to our compose color so just that we have two on these two different options here to compare if we now go to our UI in main activity that's just an empty compose project here and on the one that we first of all get a reference to review model which is view model here and for that I do have a dependency that I included already so just for dual reference let's open that um these two dependencies the runtime compose one is to safely collect flows and compose I will talk about that a bit more when we get to that and this one here is for the view model for getting a view model in a composable context like this here and yes we now actually get to getting the state from The View model so first of all we have our compost date oops compose color is equal to viewmodel dot compose color that's pretty simple since we directly deal with the compose State here compose can also work with that obviously if we want to get the state flow as a compose State however we need to do that a little bit differently and that is flow color let's call it like that and we say by viewmodel dot color which is our state flow collect as state with a life cycle or collect as state I am honestly not too sure what I want to use here so the difference is that this approach properly considers all the lifecycle changes so there are some life cycle issues that can happen if you collect flows in the UI and that one uses this something like repeat on lifecycle there's an API for that to safely collect flows and this new collect as state with the lifecycle function considers that however it's still experimental if we add this as you will see and we need to opt into the experimental lifecycle compose API which I'm always not a big fan of doing so you should also be fine with using collect as state I'm actually not sure if there is actually a difference when we just talk about State flows not sure if you can really lose some kind of emissions I don't think so um so I personally use this one to be honest even though uh if you listen to Google the other one is the more correct one but it doesn't feel correct if it's experimental and if we don't want to use these two values we can actually just create a little box with a background so let's say a modifier is a modifier filmic size we then say background wrap that into a color and here we simply assign our flow color for example and let's make that clickable and here we Simply Save Your model generate new color so the background color changes when we click on that box and if we then launch this here on my device and take a look we should be able to actually click this background and change the color which works perfectly fine with our flow version and of course also with the compose color so if we change this to compose color it obviously will also work if we relaunch this take a look here now we can also collect this so these two approaches now seem pretty much the same however there are some big differences and some advantages that one of these approaches actually clearly has over the other and if you watch my past videos where I build some real projects and compose you mostly saw me use compost dates directly in a view model and the main reason I did that was that it's just a little bit less code as you can see so we don't need to explicitly declare two properties or two Fields here for one state here we can just say that's a private set and that'll work perfectly fine and of course in the UI we also don't need this buy collect as state so that was just a little bit shorter however over time I actually changed my opinion on that and I realized how much better it actually is if you use State flows directly and I want to now show you three major reasons I see in that approach and why it's a clear recommendation from my site to actually use State flows in your view model and keep them pretty much composed State free reason number one why esters doing that is that using flows allows you to use flow operators and I've been starting to use these more and more and just realizing how awesome they are if you are able to use things like map filter or combine all these powerful flow operators you actually don't have with compose data for example if you have this color State and you want to have another color state that might be derived of that state for example you want to kind of do something with that color or transform it then you could have something like rad value for example so how rad this color is actually that you changed and you could simply say that's color dot map and here yeah well with this long it's a little bit difficult but you could then do something with that long and map it to a different value and then you could say state in and you could have yeah another state flow that's derived of that color State flow so whenever this color changes then this red value will obviously also directly change and I go more into detail in this in a video that I linked Down Below in these flow operators I really like and what the state in actually means but that's just one thing why I stopped using compost a directly in the view model because you can't do that with compose date compose date is simply just the the type of variable that you declare here and with a long you of course don't have this operator since it's not wrapped in a flow or so but let's get to reason number two why flows are better in a view model and that is that they allow us to easily deal with process death to show you a little example here let's actually go back and I want to change this back to flow color I want to show you something if we relaunch this and take a look here and we click this a little bit until we get cool color for example this green one and we then minimize our app we go back to another Studio we open lockhead and here for this little arrow um actually I want to first of all select the device we want to cancel or we want to terminate and then we click on this little red square to actually terminate our application and that is how we simulate process death so process death in Android would be that the Android system decides because it needs memory and resources to kill your app if it's in the background because it's not needed anymore if we do this and it's killed and we go back and the user takes a look at the recent apps tab you can see the the background is still green and they can still go back to the app because the backside is actually restored so the current screen where the user over process that actually happened will be reopened after the user goes back and if we do this you will see the color is reset to white again and that's the pro the problem will process that your whole application state is actually lost however since the user still gets back to the location where they actually left that can really lead to some invalid and bad states of your application if the user gets to a screen where they have the left but all states actually get reset to the default and what you would actually expect here if what the user would expect if they go back that the color is still green basically the color they they actually left and we can achieve this with saved State handle interview model by simply providing this here private valsafe State handle and everything we save and save State handle will also be restored on process staff that's also why the backstack is restored since that's saved in Save State handle so what we can now do is whenever we actually update our state right here we could say saved State handle that or rather like color so we say the we want to change the color field of our safe State handle and we set it to our new color and the advantage is that Save State handle has a function that directly returns a state flow for us so if we simply remove this mutable version here and change this immutable version to say statehandle. get State flow the key is color and the default value is white again like this then as soon as we change a value and save State handle and assign a new value here this will trigger the state flow that it returns and we also don't need this mutable version anymore since we can now update our state like this and this will survive processed that so if we remove this and we relaunch this take a look here we click this a few times for example here and we go back we go to lockhead and we turn it our application again we go back and open this I think I turned it without minimizing before let's do this again um let's leave it here again we'll minimize this show when I did and now if we go back we should be able to still see this bluish color because we restore it from Save State Handler and you can see that's exactly what happens so it's not white again however if we want to do this with compose and compose day directly if we want to restore that from Save State handle that of course also works but it's a little bit more difficult so what we would need to do in that case is in instead of this state instead of declaring it like this for the default value we would need to say safe set handle that get we want to get the color value we would need to say hey that's a long and if that doesn't exist so for the very first launch of our app there won't be this entry and that's called color and then we would still need to set it to a default color and if we then go back to main activity and we change this flow color to compose color relaunch our app then we should also still see that we can survive process depth minimize this go back to the studio lockhead terminate the app and here we want to go back oops and there we go we restored it however the disadvantage of this approach of using compostate now is that we actually have to update both these values because there is no way for us to actually get a compose State out of a state flow so there is no get or collect as composed State function from safe State handle no we actually need to execute this so we need to update the color in safe State handle and we need to update the state itself as well so you would effectively need yeah two lines for every single state update or you make that a separate function but then you need a separate function for that which is of course not ideal so that's also a reason why I clearly recommend using State flow so we can get rid of this and this and all we really do is yeah have an immutable version of a state flow exposed to the UI that we get from Save State handle and we just need to update Save State handle here to be able to survive process death and a third reason of why this is the superior approach is that you just keep your view models composed free and that just makes them more reusable than if you would yeah kind of couple them to a compose UI because you could also use a view model in a non-composed project this way if you use State flow and I'm actually not sure if you can share view models between IOS and Android if you use kmm but if that is possible I'm just not deep enough into kmm yet if that's possible then this would of course be much better if you have your view model composed free because the iOS site does not support compose yet but yeah State flows or Flows In general are a kotlin concept which would work with kmm and if that was helpful for you then consider subscribing to this channel to actually get two of such videos every single week to make you a better Android developer also if you want to learn more about these flow operators I talked about then consider clicking on this video to learn more about that and make your flows cleaner foreign
Info
Channel: Philipp Lackner
Views: 34,858
Rating: undefined out of 5
Keywords:
Id: T8vApYJlW8o
Channel Id: undefined
Length: 13min 58sec (838 seconds)
Published: Sun Sep 25 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.