The BEST Way to Implement a Search In Jetpack Compose - Android Studio Tutorial

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 show you what I think is the best way to implement a search in Android so this will be a very flexible approach for implementing a search so you can very easily then configure that and adjust it to your needs so to just show you what we'll build here we just have a list of some persons here and we can then easily search for one for example for Philip then there is a little bit of delay we see a loading animation and it will then show our name we can remove it again it will show all names if we search for for example just P then it will show all persons with the letter P in it we can also very easily Define custom search rules for example if we type the person's initials PL it will also find that person and as you can also see there's always a little bit of a delay for 500 milliseconds after we actually change the text so if you for example have a network query and you don't want to execute that on every single kind of keystroke then with this approach we'll first of all wait until the user finished typing and then we will fire off the search for this we will use a very cool approach with kotlin flow operators which which you will learn about in this video so let's dive into an empty jetpack compose product here in Android studio and the first thing I want to do is I want to create a main view model so the search Logic will happen in our main view model since that's the UI mapping logic so we create that class here make sure that's the view model and here we will Define our different states which states do we need for this well on the one hand we of course need a state for our search text so we say private bar underscore search text is equal to mutable State flow and that will just be an empty string by default we then have our public exposed version of this search text which you can set to search text as state flow so just that we make sure that the viewmodel can change the mutable one but the UI should not be able to change it so we just expose this immutable version so let's go ahead and create the next state which will be for is searching which we'll use to show the process bar or hide it and that will be immutable State flow initially false so initially we're not searching obviously and then we also do the same stuff for is searching is searching as state flow and finally we do need one more state which reflects our list of persons that we want to show and for that we of course first of all need a data class person so the real project that class would likely go in your domain layer for the the sake of Simplicity I will just keep it in the same file here each person will have a first name which is a string and each person will have a last name which is a string and then we can take this class we just created and also create a person's state so mutable State flow off a list of person initially it's an empty list we will yeah actually Define some kind of default persons here but that could also be just a list that comes from your API or so I will not go ahead and create the exposed version of persons yet because that will be the version we will apply the flow operators to so it won't be as simple as this but I will explain that when we get to it and we will get to it in a moment but first of all I actually just want to paste my predefined persons here feel free to Define your own ones or just copy this from my GitHub repository which you will find down below of course as usual um so what do we actually need before we can implement the actual search Logic I like to have a function that defines if a certain person matches our search query or not and I want to Define that function here in our person class since it's kind of business logic and we can say for example does match search query we pass our query here simply as a string and it will then return a Boolean whether we want to include that person or search results or not and this will really just be an example of what we could Implement here what I will do is I will have a list here called matching combinations which will be a list of strings because we want to be kind of as friendly or convenient to our users as possible so if the user for example searches for Philip lagner without a space we want to include that in the search results if they write that with a space we want to include that and as I said we're going to implement the custom rule if research for just the initials then we also want to include that in the search results and these kind of different combinations will Define our list here so on the one hand one combination would be that we just have our first names written just before our last name we can then also have the same with the space in between and we can have the same um with just the initials so the first character of our first name and the LA the first character of our last name um of course this was what crashed here if these strings would be empty I will just assume they are not but of course in real app you need to do some more validation here and then to actually return whether we want to include that person or not we can return matching combinations a DOT any so if there is any combination for which this expert this Boolean that we Define here in this block is true so we want to find if there's any combination where the combination contains our search query and we also want to say ignore case is true so it doesn't matter if we if the user writes the query in uppercase or lowercase so we just go through these three strings here and check okay if this string actually contains our query for example if our query is um IP then this will be true for Philip because Philip obviously contains IP so I think that should make sense we then want to go up to our review model again and to find a function on search text change which we'll just call from the UI whenever the user tapped something and here we just say search text that value is equal to text and now we can get to the exciting part and that is actually applying the search Logic and I want to do that with a flow operator or with a few flow operators which we can do here so we want to specify persons which is the exposed version of our person's State and we always want to trigger our search when our search text changes so we need to make this dependent on our search text State flow and then we want to call that combine I want to combine it with our person's state so what this will mean is that this block will always be called if either the search text or our person State changes say we get a reference to our search text and to our current person state so that way if we change our search text then we can now map the result of our final exposed persons list to whatever we specify here and if we change our person's state for example if we load more entries from the API then this will make sure that we automatically apply the the current search query to this and in here we want to check if our text so our search query is actually blank so if we didn't type anything because then we simply want to map this to our person's list as it is so we just show all persons if the text is black else so if the user types something that is not an empty text we want to take our persons and want to filter these because we now effectively want to search for something and what is the condition we filter these four well we can simply say it dot does match search query and we pass our query here if you need to have this as really scaling logic what you could also do is you could create an interface called searchable for example which every class then implements that is in a list that is searchable because that way you could effectively also make this a list of searchables or kind of any parent class you implement which then has this function here does match search query but I think yeah if you want to have some kind of more individual Behavior you will need this function for every single class independently and we can then say okay down here we will have state in which will effectively convert this to a state flow because right now if we would not have this take a look on here then we just have a normal flow but we're on the state flow we want the flow to keep the latest value and cache it so that is why we use state in to convert the normal flow to our state flow we pass our v-model scope so it will launch the flow in our view model scope sharing started will be sharing started while subscribed and will pass five seconds so that if the Subscribe and collector from our UI disappears this block and these operators will still be executed for five more seconds and then finally the initial value will just be our person's dot value so the initial value we specified in here and by the way we can also replace this with our all persons list that we defined down below and right now what this will do is it would yeah it would pretty much be an instance search so if you just want to implement a local search and the search is not very CPU heavy like here then this is the approach that I would suggest here because yeah the user will instantly see the results and before I will show you how you can also add some kind of delay and search animations I want to try this and Implement that in our UI so let's go to main activity and actually Define a column so we will stack a text field on top of a list the modifier for this will be modifier film X size we then want to go ahead and create a text field where the value is actually what we now get from our viewmodel so let's create that first value model is equal to view model and the green one here and you will probably not have this function here menu model if you don't have that then you need to include a dependency that I already included which is pretty much this lifecycle view model compose dependency if you're free to write that off now or copy it over from my GitHub if you have that I want to go in here and say we have our search text by viewmodel a DOT search text collect as state Alt Enter to import that and that will automatically update when our state flow changes we then also want to have our person state by your model persons collector State and when we're already doing that we can also do that for our is searching Boolean which we're not using yet collect a state like this and then for our text field the value of that will of course be our search text on value change will be viewmodel double colon on search text change so we just update the search text in our view model we want to make sure that it fills the whole width of our screen and we want to make sure that the placeholder is something like text search or whatever you want to use as a hint for that text field and let's also add some padding to our outer column of 16 DP import TP pressing Alt Enter and below this text field let's have a spacer of 6 CDP height and then we have our lazy column that will show our prison list um so let's actually add a modifier to this laser column modifier is modifier Dot filmex width and for the height we use a weight of one F so it will just occupy the remaining space of our layout then in here we will have an items block since we want to display a list of items and that will be our person's state and for every single person we can now simply display a text composable very simple where the text will be person DOT first name space and person oops person dot last name like this we can then also add a modifier modifier.filmax with and we say each item has a padding of just vertical padding actually of 16 DP because the horizontal padding is already added from this outer column and that should already be enough to have a working search if we Now launch this on my emulator take a look here there's still the old app and wait for Gradle to actually finish building there we go here's our search field and if we now search for something we should be able to see instant results so Philip yes that is working perfectly fine the initials are working for your search for Chris then that's working for yeah all these names are working for our search but what if we now have a search that requires um a network connection or rather a search that makes an actual HTTP call to your API and the API responds with the search results then you definitely don't want to make that API call on every single keystroke here or the same would apply if you have um if your search for example depends on a very complex database query then you also probably wouldn't want to have this instant search but rather some kind of delay to give the user time to actually finish typing so in that case what we can do is we can apply a very simple flow operator in our main view model to our person's State flow and that operator is called debounce so debounce will actually take in an amount of milliseconds which you can set to 500 for example sample and we need to add this flow preview annotation here so I'll enter opt-in for this and then the warning will go away but this debounce operator will do is whenever the search text now changes this will kind of add a delay before the other blocks are actually executed and if the search text changes before that delay is over the old kind of emission will be canceled so if the search check changes and it does not change again within the next 500 milliseconds then this combined block will be executed so in our case it will be executed for the very last keystroke where the user does not type for 500 milliseconds and of course you can very easily customize that amount and change it to your needs let's change it to one second so it's just a little bit more obvious when we try that out launch this again and then take a look in here there we go if we now type something like Philip then one second okay and now it actually shows our search results um so that's very cool one second it shows both search results so that's a very easy way to implement this kind of behavior let's now also say we actually have our Network wall and we want to show a progress bar when we're searching for that we already implemented our searching Boolean and yeah we basically only need to change that before we trigger this combined block and after it so before we can say on each is searching that update and we update it to True here since now we start searching and here I would always use update to update the value in a thread save manner since yeah in these flow operators we we are on a different thread or we might be on a different thread than our view model it is running in so there could be potentially race conditions that happen when updating this but by using update we make sure that can happen and then before our state in we also want to have an on each again where we say is searching that update and we update it to false again then going back to our main activity we actually only want to display our lazy column if we are not searching so if we are searching we do this and else we can actually show our lazy color if we're searching let's just have a box modifier fill Max size and we say we have a circular progress indicator where we set the modifier to modify a line and we put it in the center of our screen if we then launch this again take a look here then you will be able to see if we now type Philip you will actually not see any animation because the search is still instant because this filter function directly returns since it's so fast to simulate the network call we could add some artificial delay here let's say two seconds relaunch this take a look and now tap Philip then progress bar will appear and after that it will show our search results so new real life scenario instead of this delay you would actually need to make the network call and then filter based on the results you get from that so I hope you liked this video and learned more about floor operators and searching if you did then you will definitely also love my Advanced premium courses about Android development that will teach you how you can become an industry-ready Android developer if that sounds cool to you then you will find all these courses in the first link of this video's description and apart from that I will wish you an amazing rest of your week see you back in the next video bye bye foreign
Info
Channel: Philipp Lackner
Views: 31,756
Rating: undefined out of 5
Keywords:
Id: CfL6Dl2_dAE
Channel Id: undefined
Length: 16min 59sec (1019 seconds)
Published: Wed Feb 08 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.