Making Our Service a Foreground Service - MVVM Running Tracker App - Part 12

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 make our service of fall ground servers the difference between a background service and a foreign service is that a foreign service must come with a notification so what Foghorn actually means here is is that the user is actively aware of our service running because he will see that notification that our service is running and the big benefit of a foreign service here is that it can't be killed by the Android system because we could also use the background service here theoretically and that would also work but if the Android system needs memory then it might happen that it kills your service and there is no way to completely prevent that with a background service but if we use a foreground service that service is basically treated like an activity that is in the foreground and the the Android system will also not kill your activity that is currently in the foreground and in this case a foreground service is really the best option here to choose because the the user should be actively aware of the service tracking his location and it would also suck if the user is in the middle of his run and then suddenly the Android system kills the service and all the data is lost but right now our service is just a normal background service and to actually make it a program service we need to explicitly launch it as one and of course we also need to create a notification with which we will launch this foreign service so whenever you want to show another vacation then we need to make sure to create a channel for that a notification channel or at least for Android Oreo and later and for that our query function instead of our tracking service class that is called private function create notification channel and that will take a parameter which is our notification manager which is of type notification manager of course and in this function we just want to create our channel so well channel is equal to notification channel and here we need to pass an ID for that channel and name and an importance and for that I want to create constants in our constants file first of all a Const well for our notification channel ID which is a string by the way and I will set that to tracking channel then we will have a constable notification channel name which I will set to tracking and we will also have a Const Val notification ID so for the ID of an individual notification and I will set that to one and really make sure to set that notification ID at least to one I struggle hours and hours to solve a back when I had that because I set it to zero and that doesn't work for notification IDs you have to set it at least to one so make sure to do that otherwise nothing will work and I really spent so much time to figure that out but yeah you have to set it to one at least but if you've done that we can go back to our tracking service and pass those parameters to our notification channel first of all that is our notification channel ID then our notification channel name and for the importance let's actually move that in the next lines and for the importance we want to pass importance low and import that from notification manager and it's also very important to choose importance low here and nothing above that because for every notification we send and we will send quite a lot of notifications in this app because each second that passes needs its own notification because we want to update the time later on and if we set the importance here to something above importance low then that means that the notification will always come with a sound so that would mean that each second so each time we update our notification the phone would ring and we of course don't want that so make sure to choose important slow here and as you can see we get an error here because this notification channel can only be created above android oreo or on android oreo so let's press alt+ enter here and add this requires api oh annotation and then the error will begun and afterwards we want to use our notification manager we passed as a parameter and call dot create notification channel and simply pass our channel that we created here and then we can go above here and create another function to actually start or a foreign service which will be a private function start foreground service doesn't take any parameters and in here the first thing you have to do is to actually get a reference to our notification manager so we can call that create notification channel function so let's write val notification manager and set it to get the system service context dot notification service and also cast that as a notification manager so if you don't know what that notification manager is that is just a system service so a service of the android framework that we need whenever we want to show notification so we just get a reference to that system service and then we create our notification locally here in our app and then we basically pass that notification to the notification manager so the Android system can actually show our notification so next we can actually make a check here if we are on android oreo or later so if build dot version that sdk int is bigger than or equal to build dot version code 0 so android oreo in that case we are on android oreo or later and in that case we want to create our notification channel and simply pass our notification manager here so next we can actually create our actual notification let's call that notification builder and set it to notification compat dot builder and instead of this we need to pass the context which is just this and the channel ID so the ID of our notification channel and here we can simply pass our constant again notification channel ID and then we can call functions on that builder just as usual with the ad builder pattern first of all we want to set auto cancel to false that will just prevent that if the user clicks on our notification that the notification disappears we always want the notification to be active and that's why we have to set Auto cancel to false here then we want to set on going to true which means that the notification can't be swiped away we want to assign a small icon which I will get from our the drawable dot run ice you run into import our here and then choose icy icy directions run black this one you should already have that if you got the code from a github repository then we want to set the content title so the title of our notification to running app and finally the description of our notifications so set content text so that is just the actual content of our notification to zero zero colon zero zero zero zero so that is just the initial time obviously and we will update that notification later on with the new time so each second we will update it and assign new value to that content text here and as the last thing we need to pass to that notification builder is a pending intent a pending intent is used here to open our main activity when we click on our notification and in our example the user expects to open the tracking fragment when he clicks on that notification but in general if he would click on that and we would just use a normal pending intent and lead him to our main activity then the set up or the run fragment would show up because those our initial fragments that show up at first so we need to write some logic that actually leads our user to the tracking fragment and whenever we create a pending intent we also need to pass a normal intent to that pending intent and to that normal intent we can attach an action that we can check for when our main activity is launched if that action is to attach to that intent the activity was launched with and if it was then we can simply navigate with navigation components to our tracking fragment and I know that sounds really complicated right now but let's actually start with it it isn't actually that complicated let's just add an action here in our constant files in our constants file transfer action show tracking fragment and also assign the value of that to itself and now if we go back to our tracking service I want to create a function here that just returns are our pending intent so private function get main activity pending intent and set it to pending intent pending intent the get activity and here we need to pass our context which is just this we need to pass a request code which I'll pass you are here because we don't even need this request code and here you can see we need to pass a normal intent to that pending intent so let's create that normal intent here we also need to pass the context here which is this then this intent must launch our main activity so we need to pass our main activity not that one main activity double colon class to Java import main activity here call it also afterwards and set the action of that intent so action it dot action to our action show tracking fragment that we just created in our constants file and we also need to specify a flag here for that pending intent which is flag update current and input that flag that just means whenever we launch that painting intent and it already exists it will update it instead instead of recreating it or restarting it so what we can do now is we can go into our main activity and whenever we get a new intent in that main activity we can check if that action is attached to that intent and if it is we simply want to navigate to our tracking fragment but right now we don't have an option in our nav graph to be able to navigate to our tracking fragment from wherever we are and to actually accomplish that what we need to do is to define a global action in our nav graph so let's go inside of our arrest package here and open our nav graph in the navigation package this one here and here we want to go inside of our code tab so we can see the actual XML code and in here we can define a global action which means we can execute that action from wherever we are so we will create a new action tag here give it an idea of actually global tracking fragment then we need to specify the destination so app colon destination and just specify to which fragment this action should lead and that is just our tracking fragment here so add ID slash tracking fragment and we also want to set launched single chop to true if you don't know what launched single chop does is that we'll just make sure that we don't launch a new instance of our activity because if that would happen if we would launch a new instance of our activity every time we click on our notification then of course that new activity doesn't have the data of the old activity and we don't want that because all of our views and all of our data would be reinitialized so that's why it is super important that we actually set that launched single top attribute here to true anyways now we can go back into our main activity let's open that and here I want to create a function a private function navigate to tracking fragment if needed and we has an intense to that function actually that will be an honorable intent here instead of this function we can check if intent dot action so if the attached action of that intent is equal to action show tracking fragment imported action so if that action is attached we know that this activity was launched by a notification click and in that case we want to navigate to our tracking fragment so we use nav host fragment dot find nav controller that navigate and here we need to pass the ID of our action we don't want to navigate to or the action we want to execute so our ID dot tracking fragment tracking fragment and we choose that global action tracking fragment here so now it could be that our main activity was destroyed but our service is still running and if we then send that panning intent that would mean that our main activity will be relaunched and in that case it will go inside of on create again so what we need to do is we need to execute navigate to tracking fragment if needed inside of or on create function and pass the intent the activity was started with but if the activity wasn't destroyed and we used that pending intent to launch it then it won't go inside of on create again instead it will call on new intent instead so we also need to execute that function inside of this on your intent function and past the intent that is passed to this function so in both scenarios we need to check if that action is actually attached to that intent but that's actually it for our main activity now we can go back into our tracking service and you can see we now have that function that returns our pending intent and we can use that to add that pending intent to our notification builder so set content intent and just use get main activity pending intent here and then we can finally launch our grant service by writing start of foreground this function don't call a start foreign service that will be a recursive loop here because that function is called like that so just use start fragrant here we want to pass our nullification nullification ID not the channel ID we want to use that modification ID and as a second parameter and we need to pass our actual nullification which we created before so we use notification builder build so that will just tell this service that it is a foreign service or it will start it as a foreground service with that notification that we created here before and now the only last thing we need to do here is to actually call this function instead of our service class when we retrieve that action start or resume service and since this action should start or a service if it was sent for the first time and resume it if it was already running so if it is in the past state we also need a boolean here that tells us if this is actually the first run so far is first run and we set it to true of course because initially that is the first run and instead of our action start or resume service here we want to check if is first run so if we start the service then we simply want to use start for one service and set is first run to false and in the else block right now we don't have anything we can just use a lot here timber daddy resuming service and then we can also remove that log I know that was a lot of new stuff in this video I just want to make a quick little recap because of that so we created our start for grant service function here that makes use of our notification manager to create a notification channel for devices above Android Oreo and Android Oreo itself and then we use that notification builder to construct our actual notification because we have a full run service here we also need to launch that service with a notification whenever you have a foreign service you must do that and for that notification builder we needed to create a pending intent that leads us to our manic when we click on that intent we created that intent in this function here and because by default our tracking fragment won't show up if we launch our main activity we needed to take some extra steps so we attach that action show tracking fragment to that intent that we put inside of this pending intent object so whenever our main activity is launched with a new intent either in oncreate or in our new intent we check if we need to navigate to the tracking fragment so that means if that main activity was launched by a click on our notification and in that case we simply use our navigation components library to navigate to our tracking fragment so let's actually run our app and try out if everything is working take a look in our emulator here navigate to the tracking fragment and yes I allow the permissions here I uninstalled the app recently go inside of the tracking fragment and click on start and I can see our service was launched because the notification shows up and if we now minimize our app then the notification is still there of course and if we click on it our tracking fragment will open but also if we navigate back to the setup fragment for example and minimize the app and click on the notification then we will still be led to our tracking fragment and also if we completely close our app and click on the notification then we will also be led to the tracking fragment so that would be the case in which that navigator tracking fragment if needed function is executed because our app was destroyed or our main activity was destroyed so it will start in oncreate again but if we just minimize the app and click on running app again on that notification then uncreate won't be called again instead it will call this on new intent function so yeah I hope this was understandable for you and you learned something new if so please let me know in the comments below and also if you have any questions don't mind asking them below and I will try my best to answer them if you haven't already please subscribe to my channel you don't miss any new videos have a good day see the next video bye bye [Music]
Info
Channel: Philipp Lackner
Views: 12,194
Rating: 4.9849906 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, dagger, dependency injection, 2020, google maps sdk, google maps, maps, location, my location, location tracker, polylines, viewmodel, livedata, repository, coroutines, service, foreground service, room, database, best practice, tracking, fitness app, health app, sports app, app, application, dagger hilt
Id: JpVBPKf2mIU
Channel Id: undefined
Length: 20min 21sec (1221 seconds)
Published: Wed Jul 01 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.