Tracking User Location in the Background - MVVM Running Tracker App - Part 13

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey guys welcome back to new video so in this video we will implement the full functionality of our user tracking that means we will get the users location on a consistent basis and then simply save those locations to be able to later observe on changes on those locations so whenever we get a new location by the user then we can simply react to those changes in our tracking fragment and to be able to observe on those changes we will have live data objects here inside of a companion object in our tracking service so we can easily observe on those from the outside first of all I want to have a live data object with our current tracking States so just a boolean if we are currently tracking the user location or not that will be a well is tracking and we're going to set that to immutable live data of type boolean so we will just whenever the tracking state changes post the new value instead of this is tracking live data and then we can observe on those changes from the outside and we will also have another life data here for this video which is a little more complex than this boolean life data because this life data I want to create here will hold all the tracked locations from a specific run and the intuitive answer here is to just save that as live data of list of coordinates so we just have a list of several coordinates and then we will simply draw a line later on after those coordinates inside of that list but this intuitive answer won't help us much here because it will produce a bug later on if we implement it like that and why that happens or why we why that is not enough I want to show you in my emulator in the actual final app here you can see I can simulate a route that the emulator will run let's click on play route and start a new run then you can see that the tracking stars it's working perfectly fine and a single line here consists of several coordinate so that is basically just a list of coordinates and that is pretty clear I guess but if we now click on stop then the emulator is still continuing on that route but we don't track right now because if we now click on start again so we continue that route then of course a new line needs to start and it shouldn't connect this line with the new line instead during that time inside of this window where we didn't track we also don't have any coordinates and we don't want to display them in our map because let's say the user run and then he stopped the service then he walked a little bit and then he clicked on start again so he wants to continue running in that case we of course don't want to connect the old run with the new run so in the end we can say that each single line we have here is a list of coordinates but since we have several of those lines that live data that we want to create now must be a live data of list of lists of coordinates so we have a list of several lists that hold coordinates and that sounds pretty complex right now let's actually stop that tracking here and it will actually get clearer when we implement that so let's actually implement that that will be a well called path points so just the points on our run path and that will be immutable live data of type mutable lists of type mutable lists of type let long if you don't know what let long is that is just the coordinate format of maps since the earth is not flat and rectangular well who knows but you cannot simply have an x and y coordinate format for describing coordinates on the earth and that's why we have that special lat/long coordinates format here so again because this is really a complex type here first of all we have our mutable life data that just allows us to observe on changes of this type later on so whenever we get a new coordinate in of our polyline list then we can observe on that change we can see that there is actually a change in our tracking fragment and draw the actual line on our map view then we have that mutable list of mutable list of lat/long one mutable list of let long here is just a simple polyline just a line of coordinates on our map and since we can stop our service and resume it we simply have several polylines or we can have several polylines in our map so we have a list of polylines I think if we describe it like that that immutable list of that long is actually a polyline then it's much clearer so what we could do here is actually define a type alias for that that is just a different name for that complex type and we can do that by writing type alias and let's do that for a polyline and define that as a mutable list of lat/long and then we can also have a type alias for several polylines so polylines is equal to a mutable list and now we can say a mutable list of Tolley line and if we now take that whole block here and replace it with polylines it's actually much clearer so I hope that is clear now and since we just created that life that are here and here that life data just doesn't hold any value right now and that's why I want to create a function here that just posts initial values inside of those live data objects so private function post initial values and inside of this function we just want to use our is tracking live data and call post value and initially we are not tracking so we post the value false and we want to use our path point live data and post the value mutable list off so just an empty list because we don't have any coordinates in the beginning the next function we want to implement here is a function that adds an empty polyline so an empty list of lat/long coordinates at the end of our polylines list because when we post our tracking and then we zoom it again then we simply need to add that empty list first before we can add coordinates in it and let's actually do that down here that will be a private function add empty polyline and we are going to set it to path points dot value so the value of that life data that is in this case our whole polylines list so all of our polylines and we call that apply on that and here we can just call add so we want to add a list to that path points and we want to add an empty list so just mutable list off and then afterwards we want to use half points dot host value and use this because we're instead of this applied log here this refers to this current polylines object and because we added that new polyline there is a change so we want to post the new value of that so our fragment will be notified about that change later on but what could also happen is that this value is null and in that case we won't execute that block so we won't add an empty polyline in that case we also need to take care of this case in case it is now because then we simply want to post the initial polyline so just the first empty polyline let's use path points dot post value mutable list of type mutable lists off so here we just initialize our polylines list and we also add the first empty polyline inside of that list so we can easily add coordinates to that and start the tracking and then we can simply call that at empty polyline function inside of our star fragment service function because when we start our service we of course want to I'm at that first polyline that first empty polyline so simply call that function at the start of that start program service function and now that we have that function that adds an empty polyline at our polyline list we also need a function that adds a coordinate to the last polyline of our polyline list and for that I will create another function a private function at half-point and that will take a location as a parameter which is of type location that is just very similar to a lat/long coordinate but it holds more information about a specific location but we only need the latitude and longitude coordinates of that location parameter here but that's just the type that we get later on when we get the user's location so instead of this at power point function we want to check if that location that we got here is actually not equal to null and I forgot to make it a nullable type here that is important because the locations we get later on will be nullable too so we simply use location and check with let if that is not equal to null so if we go inside of this lab block and that means that location is not equal to not and now as I said we have that long coordinates inside of our polyline instead of a single polyline and here we have a location and that is not a lat/long coordinate right now so we someone need to convert that but that is very easy to do we just have a well position and set it to new led long and that consists of two parameters the latitude and the longitude we can get the latitude by writing location dot latitude and location dot longitude and now what we want to do is we want to add this position to the last polyline of our polylines list so we will use our path points live data again dot value question mark apply so we make that null check here and here we want to get the last polyline of that and since that is a mutable list here we can simply use last year to refer to the last index of that list and since that last index is also list the list of let long coordinates we can add a new coordinate here and simply pass our position and since we changed something in our path points like that we also want to post a new value so path points dot post value and simply write this and that's already it for this ad path point function the next step is to define a location callback because 2 X get those location updates what we will use here is a so called fused location provider client that is just something that we can use to request location updates so it will basically deliver us on consistent basis with new location updates whenever the location changes or we can set an interval for that when we want to get a new location update and then simply deliver them to us and for that we will just need that callback to get the actual location results let's define that up here Val location callback which is an anonymous class so of type object : location callback call the constructor here and here we press ctrl + o and we want to implement that function on location result then we want to rename that p0 parameter here pressing Shift + f6 to result because that's a little bit more clear of course and in here we want to check if is tracking that value and also assume that this is not equal to now because at this point there is no way this can be now so this line just means we want to check if we are currently tracking because only then we want to add coordinates of course and then use that result parameter here so the location result to make an object here and use locations because that will hold the locations of that result which will usually only hold a single location but that is still a list so we want to make a null check here again in case those locations are now if they are not now let's actually call that locations if they are not now we just want to loop over them so for each location in locations and simply call our function at path point and past that location so all that callback does now is whenever we retrieve a new location which is saved in that result variable we just add that location to the end of our last polyline and now the last real function we need to do for this video is a function that will up location-tracking so whenever that is tracking value here instead of our life data changes we also want to update the location tracking because if it changes from false to true so if we want to start a location tracking we need to explicitly request those location updates and if it switches from true to false so if we stop the location tracking we don't want those update anymore and for that I will define a function that will be a private function update location tracking which will take the is tracking parameter as a boolean in the parameter list here and inside of this function we want to check if we are currently tracking so if is tracking is equal to true if it is we also want to check if we actually have the location permissions so if we are allowed to track so let's make another if check here if tracking utility that's why we have that function that has location permissions and context is just this year since we're instead of a service class there is no problem so if we have the location permissions then we want to request location updates and for that we need a location request which will just hold some parameters regarding our location updates I will call this well request and that will be a location request dot apply and here we can make some changes on that location request first of all we want to set the interval of that location request so how often will we actually get our location updates and for that I want to set a constant in our constants file and now we kinda have to set it the average interval at which we will get location updates that's not super accurate but let's set that by writing a consul location update interval and I will set that to 5,000 milliseconds so every 5 seconds we will get a location update but what this location request also takes is the fastest update interval so the interval which is basically the lowest interval possible so we will never actually get more updates than this fastest location interval let's call this fastest location interval and I'll set that to 2,000 milliseconds so two two seconds so it will never happen for example that we get location updates each second at minimum we will have that two seconds interval which is just to save memory resources but as I said that really differs it could be that we receive a location update after 3 seconds after 6 seconds and that is just a value that is approximately to the interval that we set here then we can go back to our tracking service and assign the interval here to location update interval then we want to assign the fastest interval to fastest location interval and what is also very important here is the priority which we will set to priority priority high accuracy import that here which just means we want to get accurate location results here and as I said to actually be able to request those location updates we need a so called fused location provider client let's actually scroll up and create it up here which is Lady Navarre fused location provider client and instead of our on create function from our service we want to initialize that fused location provider client so let's overwrite on create here and set that fused location provider client to new fused location provider client which takes the context so we just passed this year and then we can scroll down again to our update location tracking function and after that applied lock we want to use that fused location provider client and call that week rest location updates and that now takes our location week rest as a parameter so we just passed that request here it will take the callback we defined down there so our location callback and we need to pass the looper which is just blooper dot get main looper and as you can see it throws us an error here because it wants a permission check by us but we actually did that permission check here but since we do it with that easy permissions library it doesn't recognize that so let's click on that press alt' + enter' and suppress this warning with this suppress linda annotation here and then this error will go away and now in case that is tracking variable is false so we stop the tracking then we want to remove those location updates again so let's add an else block here and simply use our fused location provider client dot remove location updates and you can see we simply need to pass the location callback here so let's do that and that is everything you need to do and now we only need to scroll up to our on create function here first of all I want to call that post initial values function here before we forget that and at the end of uncreate we want to use our is tracking live data and call that observe on that has this as a life cycle ona and that is only possible because we declared that service as a life cycle service otherwise we couldn't pass a service as a life cycle owner and as a second parameter we will pass an observer here and here we just get updates whenever our is tracking state changes and whenever that changes we want to call our update location tracking function and simply pass it here and when we start our service now then the only thing we need to do is to post the value true in our is tracking live data so that observed block here will actually be caught with the value true as a boolean then we will call up the location tracking with true and then we will simply request those location updates so let's scroll down to our start foreign service function and here we just want to call is tracking the post value true and to test that functionality I just want to scroll up to our location callback or on location result function because that's the function where we get a new location and here I just want to add a lock statement with timber timber D new location and simply pass of a location that longitude no latitude first latitude and then location dot longitude and if we now run our app and take a look in our emulator then you can see that emulate a menu here or the options for that emulator on those three little dots here let's click on those and then you can see we have a location tab and instead of this location tab we have a routes tab and instead of this routes tab we can now set up our custom routes that the emulator will simulate so if we want to do that we need to go into this text field here and type the destination where we want to simulate that route too so in my case I will just choose Hamburg here in Germany choose that one and now I can see we can start that route let's click on that icon and now we have to set up the start point and in my case that is my hometown Hannover choose that one and if we now click on safe route then we can give it a name I will just click on save here you can see that route is saved in our safe routes tab here and now we can choose a playback speed so how fast that emulator will simulate that route I will choose four times here and click on play route and now if we zoom in you can see that the position is actually walking that route or driving that route or whatever and if we now go into our emulator we will actually receive those location updates let's open lock it here and choose the correct emulator of course open the emulator here click on the floating action button and if we now click on start the tracking will start and you can see we receive location updates with the latitude and the longitude exactly as we want it so everything is working perfectly fine I hope this video was helpful for you even though this was very long but I just wanted to set up that hole location stuff in a single video because that kind of belongs together and I just wanted to have that in a single part and yeah if this video helped you please leave a like and subscribe to my channel if you haven't already have stay tuned the next video bye-bye [Music]
Info
Channel: Philipp Lackner
Views: 21,436
Rating: undefined out of 5
Keywords: tutorial, android, development, learning, programming, programmer, kotlin, beginner, mvvm, running, architecture, clean, android studio, android studio 4.0, androiddevs, android devs, navigation components, dependency injection, 2020, google maps sdk, google maps, maps, location, my location, location tracker, polylines, viewmodel, livedata, repository, coroutines, service, foreground service, background, room, database, best practice, tracking, fitness app, health app, sports app, app, dagger hilt, dagger
Id: 8ByyVW830nE
Channel Id: undefined
Length: 22min 35sec (1355 seconds)
Published: Fri Jul 03 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.