How To Handle ViewModel One Time Events In Jetpack Compose | Android Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys my name is Anna Grace I hope you're doing well and I welcome you to a new video the state handling or event handling is essential in almost every Android app at one time in the development process you will come to the point where you need so-called one-off events or one-time events such events are for example the result of an API coil and that in that case you want to show a success message another example is maybe that you process a workflow and at the end want that the user navigates back in that case you trigger an event and that event should get consumed once and triggers at the end the navigation in the Legacy Way of implementing our uis in most cases we use live data for such one-time events there was a workaround called single life event May some of you know this concept because it was hardly used and is still today widespread used in many Android apps But as time goes by they were introduce new opportunities to implement this process with the hot flows from kotlin shared flow and state flow we had a new way for implementing these one-time events however with the declarative UI approach of jackpack compose things have changed the known Android team which you may be familiar with often provides suggestions on how we could implement or should Implement our Android architectures so it came that monovivo for example on the droidcom Berlin 2022 Hilton presentation about implementing modern Android architecture and he also wrote an article called viewmodel one of event anti-patterns one of the main takeaways from the droidcon talk was that the in general a good idea to hold your view state from your view model in a data class inside the view model that view state is then presented to the UI layer and the UI layer on the other hand just presents the state in the article about the one of anti-patterns I was just talking about on the other hand he also showed us how we should handle one-time events in Jetpack compost but let's first take a look at what this anti-pattern he was talking about actually looks like in this case he is not using a shared flow but the channel but he directly says navigate to payment results screen so if this channel receives a new value which is right here we send is payment successful the result screen should navigate further so if we come to this section here he not only mentions that the state can get lost by using the approach of channels or chat flows but he's also telling the UI to take an action as an anti-pattern so that the view model shouldn't have the UI what it should do with this state the third point he mentions here is that not only the one-off event immediately and as a solution he proposes to use the state flow and all the values inside that and directly observe these values and yeah collect them and handle the events before we take a look at the anti-pattern in a practical example let's take a first look at our example app from today we have a simple UI here only a trigger event without a timestamp button and the trigger you end with timestamp so when I click on without timestamp as you can see we just received a snack bar here without any further message and if I click on trigger event with timestamp at the end we receive an event with a timestamp so these are these one-off events I trigger here a process and at the end I have a new result and I show it to the user let's start by taking a quick look at the content composable so we have a modifier a function here for starting the process with other timestamp and also one for starting a process with timestamp and then we have our loading state the layout itself is just a column we have a top bar and here a secular progress indicator which we just saw in the app example and two buttons which are only enabled if the state is currently not in the slowing state and if we scroll up we can take a look at how this stay collection here actually works and also the snack bar stuff so we have here the view state which currently only holds the is loading state and we have here our two chat flows which get collected in this lifecycle repeater lifecycle block we launched a carotene for each of these collection processes and the whole stuff is wrapped inside the launch effect so it gets only executed once as you can see for the on show process notification we show the event success and on the other chat flow we show the timestamped with within this snack bar so that is the UI handling part and then let's quickly jump into the anti-pattern view model as you can see here we have a state flow which holds the state and these two shot flows one without and one with the timestamp and here's just the function that triggers the dummy process as you can see it's just a plate placeholder delay with three second delay and here we activate the loading process and also deactivate it and down here we emit the shed flows and here we emit the timestamp which gets formatted by the get times instance of the simple date format and now that we saw how we shouldn't do it with jetpack compose how should we do it and if you recall the approach shown by monovivo we will no longer have these two sharp flows but put the event inside our main view state so we start at the main view state and here we introduce a new variable which is process finished and we just use the Boolean here initially it's false and the second one is process finished with timestamp and we used another string and initialize it also with null so that are now our two view State representations for the events and now we need to adapt the entry pattern we wanted and you first get rid of these two shell flows and now we just need to update these two lines as a replacement we will just update our view state in this case we want to say okay the process is finished and therefore we use the current state which you get when you update your view state because it's a data class we can just say copy in this case we say process finished and just call it true in the second case we can just copy this and we once again use this function for creating timestamp and we say process finish with timestamp and also set the value to the timestamp so by that we updated the view state and if you now go back to our main activity or to be more specific to the main screen we will need to adapt these two positions because we don't no longer collect from Shad floss but need to react on our view state so what we do here is we introduce a new launch effect and we say view State process finished and now here the first one we only need to call the snack Power State once again and the same goes for the timestamp case so also here view State and this time we use the process finish with timestamp and now also we use the timestamp here but in this case we also want to have the timestamp itself therefore we use select function and we say timestamp and in this block we can once again use the timestamp so that we only call it if the value is really not null and afterwards we now need also to tell the view model that we consumed the state and how we do that is we just introduce two new functions and say consume um process finished and also consume process finished with timestamp foreign [Music] we can copy this line and say no so we set it back to the initial State and here also for the process finished we say false of course we now also need to consume it therefore after we show the snack bar we say consume process finish with timestamp and here we say consume process finished so now we've migrated the anti-pattern to the style that is proposed by the Navan Android team but in my opinion a few things are off here one thing is that we always need to make sure to call the view model consume function and in the case in which we want to process the result we always need to access this variable twice and need to check if it's really not mad and so on and also have once again the problem that we need to manually call the consume process finish with timestamp function and one more thing that comes into my mind is that we can no longer distinguish between a regular state representation and a event in this case so what is what because we just wrote this code we know it but will a developer in three months denote I don't know but what if I told you that there's a library that facilitates the process and makes it clear what is an actual event in our view State and what is just a regular state representation as you can see in this documentation we have a state event which is a representation for a simple event without further content and we also have the state event with content which as you can see here for example takes an integer each of these State events can toggle between two states the initial state is consumed and the state when the event is actually invoked or active is triggered but that's not all there's also an override for the launch effect which is event effect and as you can see because it's always the same pattern we need in event and we also need to call the view model to consume this event you can import these two things event and unconsumed and after your execution block it will automatically call the unconsumed function in the case that you want to process the result you will also receive the result in your function block here so back at our example let's introduce this library in your app level buildcreator file makes sure that you have at least this version of the compo state events Library and you can also receive all these dependencies from the GitHub project I linked you down description where you can exactly copy all this code and let's go back to our main activity and now let's introduce this Library we start by migrating our main use state so for the simple event we use State event and now set it to initial state of consult we will also no longer name it process finished but process finished event [Music] and also here we call not no longer process finisher time step but also panda with event and here it's a state event with content and the content is the string which is finally the timestamp and here we initialize with consumed the next step is to go back to our view model and now there's not much to do we just need to set these values a little bit different so it's no longer true but triggered for the simple case so the event is called and for this case I will quickly using uh own variable for this one and here we will say consumed a triggered sorry and the content is the timestamp and on the other hand the other way around when we consume these events we say again here we have consumed and here also suit so now as you saw we used a different approach for these launch effects so it's no longer launch effect but event effect for that simple case and here we now need the event which is from our view State and a c process finished event and the unconsumed is on the other end this function here and we can use the function reference and now if the process block here gets executed afterward the consume process finish will automatically get invoked the next thing is also that this function block will only be invoked when this launch effect which is under the hood reaches the triggered state now for the event effect for the second case we can actually consume this pattern here copy this pattern here and say processed finish with timestamp event and now you can see that in this function block we already receive it string which is of course our timestamp and now we can completely get rid of this one also copy the consumption the correct consume function here and yeah now we can get get rid of this stuff here and only use the snack bottle stage show snack bar so as you saw this library is really handy and easy to implement even if you ask yourself now okay that sounds good but why not use the conventional State why the compose State events Library as you saw it's not only easier to implement this process for handling one-time events in Jetpack compose but it also makes it directly clear in your view State what is an event and what is this real estate representation we don't tell the UI directly what it has to do with this event but we know this event somehow needs to get consumed so it's also less error prone in the future when new developers come on the project and need to maintain this project and they don't no longer know what is an event and what is the state representation because in this example we had only like two events what is what is if you have like 20 or something like that so in conclusion I can only encourage you to try this Library out I hope you had some takeaways if you want to take a look at the full project click the link down description I link the GitHub repository where um provided all the code samples here and if you want to dive deeper you can check out also my medium article wrote for the printer Dev about this topic and finally I just can say like the video subscribe to my YouTube channel activate the notification Bell and I hope to see you soon
Info
Channel: Yanneck Reiß
Views: 9,302
Rating: undefined out of 5
Keywords: Android, Android App Development, Programming, Kotlin, Coding, Mobile App Development, Jetpack Compose, Android Jetpack Compose, Composable, Android Jetpack, UI System, AndroidDev, Jetpack, Event Handling, SingleLiveEvent, StateFlow, SharedFlow, One Time Event, Android one time event, One Off Event, Now in Android, Android Architecture
Id: 2uRtF86uWqg
Channel Id: undefined
Length: 17min 43sec (1063 seconds)
Published: Thu Oct 13 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.