How to Use Device Sensors the Right Way in Android - 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 we will dive into sensors in android so as you know android devices have quite some sensors you can use to get a sensor data from the outside world and that is what you will learn today and you won't just learn how you can actually get these values no i will actually show you my favorite way of implementing such sensor handling because you can do quite some stuff wrong there if you want to integrate that in an existing architecture i will show you an approach that makes it super easy to actually extend your app with more sensors and just to have some nice abstractions which allow you that you can easily unit test your sensors and yeah how these interact with your other parts of the app even local unit tests so just the way that i prefer when i implement sensors into an existing architecture to to make it scale to integrate it well so that you follow all the clean code practices here and the example sensor i will use here is the light sensor because that's quite easy to implement but it is as easy to extend this with more sensors by just adding a few lines of code here so even if you want to use some other sensor you can fully watch this video um this won't be specific to this light sensor all the video along that will really be only be the the last minute or so where we'll implementing the light sensor specific stuff so what will we do here we will have this sensor data and right now it's pretty dark here in my room so it will say it's dark outside but as soon as i take my phone and i um hold it in light then you can see it says it's bright outside so the light sensor is working perfectly fine and that is what we will do but if you want to implement other sensors then just feel free to watch this also if you're using xml then you can totally watch this video the implementation and abstractions and all that stuff will be exactly the same just a very minor difference in regards to the ui layer but nothing in regards to sensor data so let's first of all try to understand how i like to abstract these sensors and if you don't know what an abstraction is that is in the end just either an interface in kotlin or an abstract class and we use that to keep our code actually replaceable so that we can also easily extend that by simply adding more sensors that inherit from that abstract class and just um that you don't have the android specific code directly in a single class that you might use in your viewmodel or so because then you can't really write local unit tests for that because you can only write local unit tests if you use non-android dependencies so if you use something like the context which and which sensors need an android then you can unit test that you need to make it an instrument test which is slower all that stuff um so we will write a little abstraction which i will call measurable sensor because that's in the end what it is we select class here let me add that to git and we make that an abstract class so now we just define what a sensor should actually be able to do we don't define any functionality yet on the one hand every single sensor could either be available for a device or it could not be available because not every device has every type of sensor so you kind of want to have a boolean here to check whether a sensor is actually available for a device and i will call this does sensor exist and that is a boolean then we will have two more functions on the one hand an abstract function start listening so that will tell the sensor manager of android later on that we would like to start start to listen to specific sensors values and if we have a start listing function we also have a stop listening function that makes sense i guess and something we want to have here is a protected val actually on sensor values changed so whenever the sensor manager later so the the service of the android operating system that reports these values whenever that tells us hey here is a new sensor value for for your desired sensor then we want to trigger this callback lambda that i will create here and that will give us a list of floats and doesn't return anything and we make this null by default why does it give us a list of float well because some sensors actually give us multiple values for example for example there is a rotation sensor that determines how your device is rotated and then you have an x y and z value for that if we use the light sensor we only have one entry then this will be simply a list of one element here but just to be flexible to easily extend this with more sensors we have this as a list then if we have this lesson about lambda here we also want to have a function this time a public function to actually set the on sensor values changed listener and here we pass that listener like that and then we say on sense of values change is equal to our listener um and that actually needs to be a var of course and something that actually every single sensor needs out there is a sensor type so we need to tell android which specific sensor we actually want to access and that's something we can pass on the constructor so private val actually let's make that a protected valve because we need that in subclasses protected valve sensor type and that is an integer cool so now we have that very outer abstraction which doesn't require any android dependencies that is going to be the class the type of class we will use in our review model later on to actually get the sensor values directly in the view model and then take these and put it in some kind of state object next up we want to add another sensor class which will be android specific sensors so we will create this android sensor class here which will be a normal class here oh no actually not a normal class it will be an abstract class as well because we don't want to be able to just create an android sensor because then we still don't know what kind of sensor it actually is because what we will do is we will then have another layer of subclasses um that then inherit from this android sensor class and that will just be a class like light sensor like a proximity sensor just like stuff like that which will then make it super easy to add more sensors to our app you will see how that works if you don't understand that now uh don't worry here in this class we now need some more dependencies in the constructor on the one hand we need a private valve for the context which we need to get an instance to that sensor manager i talked about we want to have a private valve sensor feature which is just an integer and that can be used to determine whether a specific sensor exists and we actually have the sensor type we want to pass here and that will then inherit from measurable sensor and here we pass our sensor type and we're then ready to actually implement this first of all we'll override does sensor exist and here we will simply use our contacts package manager dot has system feature which is used to check whether a specific feature exists for that android device and here we want to first of all pass the feature we want to check for that is is it package manager i think yeah here feature sensor light you can already find that um that will check if the light sensor is available however we want to write that in a general way we don't want to hard code the light sensor into this class then this would be pretty pointless which is why we actually want to pass the sensor feature we passed in the constructor um that still gives us an error because that needs to be a string just like that and then it will work cool we then on the one hand want to have a private latent variable sensor manager that will be the system service from android that will report the sensor values for us and we will have a private var sensor which is also coming from android this android hardware sensor and that's not the default and that will be returned from the sensor manager once we told them to start listening and how to and which sensor we actually want to listen for so we will start with our start listening function and here we first of all want to check if our sensor actually exists so if it does not exist we simply return of this function then we want to check if this is actually the first time we call the start listening function so if our sensor manager is uninitialized in the sensor so we can check that using if double colon sensor manager is initialized and actually negate that and our sensor is equal to now then we know we called this for the first time and we can initialize this the sensor manager will be equal to context get system service we say sensor manager double colon class and we say as sensor manager and then we can assign the the value of the sensor using this sensor manager and we still get an error here what is it nothing i don't know it doesn't show me it it actually shouldn't give us an error so let's just leave it and hope it goes away the sensor actually then is sensor manager dot get default sensor actually and we want to pass our sensor type here so that is how we can assign the sensor and we actually also have an else case in which we want to simply start listening or actually let's not do this in else because we always want to do this so we will say sensor dot let and then we can say sensor manager dot register listener so we now have a sensor listener that tells us whenever the sensor value changes it will be this we will use this class here as a listener the sensor will be it and we want to say sensor the center manager yip sensor manager sensor delay normal so this also gives us an error here because this is not of type essential event listing yet so let's implement that interface um sensor event listener and now we're ready to go ahead and actually overwrite the stop listening function in which we of course want to stop listening to sensor values if the sensor does not exist again we want to return here or if our sensor manager is not initialized we just return and also we can say sensor.let again and this time we want to say sensor manager um unregistered listener actually don't need that led we can remove that and we pass this so we just remove the listener again once we call stop listening and one last thing that we actually need to do in this class is if you remember we have this on sensor values changed function and we of course need to trigger this lambda whenever we get new sensor values and where do we get these new sensor values well we registered this listener here so this class can now implement callback functions using this sensor event listener interface and we can simply override these callback functions which is called on sensor changed which gives us such a sensory event here and we say if the sensor exists if that's false we can return and else we want to check if that event that sensor type is actually equal to our sensor type so we only want to trigger this for yeah for the sensor we actually requested for then we want to say on sensorvalueschanged.invoke and well now we need to pass a list of float that will be event values and we can actually say that to list here and do we need this check here yeah no we don't and that works just fine and we still get an error here and it still doesn't show me that so i guess it will be fine if not we will get back here later but now that we have this class that just implements the logic how any type of android sensor works because this this part really does not change if you have a different sensor all that is really different for sensors in android is the sensor feature the sensor type and how many values you have in this list here and since we pass a list here we don't really care how many values there are so that's what makes this class so useful and reusable so we'll now go to our project package and create another class which i will call sensors and this will be a file in which i'll put all the different sensors we will use in our project since i'll just show you that with the light sensor let's have a data class light sensor that will take the context and that will now inherit from actually then it will be a normal class it will inherit from android sensor oops android sensor and we now need to pass the context context the sensor feature is package manager feature sensor light so now we specify the light sensor of course has that feature the sensor type is it is sensor dot type light and if you would have a different sensor you would then pass for example type rotation vector type accelerometer for the accelerometer sensor the proximity one so it's really easy now to extend this and we do get an error here because we don't implement on accuracy change that's a function we don't need but we can implement this in the android sensor class so that's a function that comes from the sensor event list as well we can simply say on accuracy changed and then we say that's equal to unit so if you care about the accuracy of that sensor then you can also get these values here we don't um and now it actually tells us here is no error anymore even though it still underlines that doesn't matter so you can see how easy that is to extend that let's just say you also want to add the proximity sensor for example then you just take this one paste it and you say proximity sensor and all you really need to swap out is this one to feature features sensor proximity and you use the type proximity sensor so that's the sensor that measures the distance between your device and some kind of object which is typically used for example to turn the screen off once you put the device to your to ear if you won't have a call or so yeah but that's how easy you can now extend this android sensor class and use a different type of sensor in your app i will remove that again and we will now of course make a use of this light sensor and see how we actually can gather this sensor data for that i will implement a little view model just main view model nothing special here just a very very simple one i actually added hilt into the dependencies so just a quick look um here we have daggerfield the plugin and kotlin capped which you need to add here if you want to follow along these dependencies and of course the viewmodel one so you can simply copy these from my github repository down below and then you're good so we will make sure that's a hill view model and we say inject constructor so what do we now inject here we want to inject a private valve light sensor and we don't say that's a light sensor because that would hard code this via main view model to always use our specific android sensors however we might rather want to actually inject the actually not we don't call it measurable sensor we still call it light sensor but it is a measurable sensor which is our um most top level abstraction here and the advantage of that is now that imagine you want to test this view model you can you don't have to pass the actual light sensor instance which you don't have access to in local unit tests at least instead you can for example write a fake version of this measurable sensor class which just simulates some sensor values for your test case and then you can have a local unit test for this viewmodel even though you use some android specific values here under the hood which you don't really use in your unit test zen so that's a pretty good thing to do that's a view model and in here we now need to think of our logic and this logic is actually super super simple let's just go inside of the nit block and we say light sensor that start listening that's something we need to call of course and then we want to say light sensor set on sensor values change listener here we get these values and since we know our light sensor will just give us a single value we can say val lux which is the physical unit for how bright something is and we can get that at the very first um index of our sensor values and if you would have like a sensor that gives you three values then yeah the first one would be for example x the second one y and the third one z and then we can say okay we actually have some kind of state here of our state by mutable state off which is false actually let's not call it state that's not what it reflects let's call it is dark so if we should show the dark theme of our app then this is true and else it's false and we choose this depending on how bright it is outside and yeah i tried around a little bit with that that's of course now very specific to here how sensitive you want to have that i will say it is dark if the lux value is less than 60 f and feel free to play around with that it really doesn't matter for this tutorial all that matters is that you get these sensor values here whenever these change and you can very easily update the state in the view model let's now make sure that we can easily inject the sensor here with dagger hilt so we go to our root package create a sensor app class and we annotate this with healed android app and that of course inherits from application then we go to our manifests and here we specify the name center app to just register that as our main application and we now need to specify a module in which we provide this measurable sensor so we can say okay a new class that will be our oh let's call it sensor module select object we need to annotate this as a module for daggerfield we need to say install in let's just make it singletons here we could also scope it to the view model so really doesn't matter for this simple tutorial and here we now specify how we create our light sensor well on the one hand we're going to provide it and that's a singleton and i'm sorry if i go through this dagger hill stuff quickly here that's really not the point of this tutorial i have a very detailed daggerfield course on my channel but i think i it's still quick to just write this here to inject this into our review model so we'll have a provide function provide light sensor that will need the application context and it will return a measurable sensor which we need to return here to so it actually knows what to inject here so even though we will return the light sensor in here there's one with our application it will still need to know the type we want to inject which is equal to this one here then going to our main activity annotating it with android entry point so we can inject our review model in here we can quickly set up our scene so we will have um yeah just a for the background the modifier is modifier filmex size we will say okay the background is actually depending on our state if it's dark the background is dark else it's bright so we have a val viewmodel first of all is equal to viewmodel of type mainviewmodel and we have our istark value this viewmodel is dark and the background is depending on if it is dark if it is dark we want to have a dark gray background and else a white background i'm going to say content alignment as center to center our text we will have in here the text will be okay if it is dark the text will be white because it needs to be visible on the dark background so color that white and else color dark gray and what else it is complaining oh i assign the of course we want to assign the color for the text and the text itself is also depending on that whether it's dark then we will say okay it's dark outside and else we will say it's bright outside and a comma that should really be it here let's just launch this and hope everything will go right if not then we will simply fix this and i will see you back once gradle finished building so there we go it says it's dark outside which looks good if i put my phone and hold it in the light it says it's bright outside so that looks like it's working pretty fine holding my hand on from this works great i hope this was an enjoyable tutorial for you and you learned how to how you can now properly integrate any type of sensor into your app so as i said if you want to extend this you just go to your sensors file and you implement another class of sensor and you just swap out this feature this type and that's it and of course how you interpret these values that you then get for this other sensor you would also inject here let me know down below how you like this video i wish you an amazing rest of the week an amazing rest of the day and see you back in the next video bye bye you
Info
Channel: Philipp Lackner
Views: 24,236
Rating: undefined out of 5
Keywords: android, tutorial, philip, philipp, filipp, filip, fillip, fillipp, phillipp, phillip, lackener, leckener, leckner, lackner, kotlin, mobile, light sensor, proximity sensor, rotation vector, sensor, feature, hardware, native android
Id: IU-EAtITRRM
Channel Id: undefined
Length: 25min 8sec (1508 seconds)
Published: Sun May 08 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.