Smartphones zitten boordevol hardwaresensoren, zoals versnellingsmeters, lichtsensoren, gyroscopen, enzovoort. Leer hoe u gegevens van deze sensoren kunt verzamelen door een barometrische logger te implementeren.
In een vervolg op de laatste zelfstudie, Apping App Components, zullen we deze keer code implementeren voor het regelmatig lezen van barometrische sensorgegevens. U leert de sensorgegevens te lezen en herhaalde gebeurtenissen zo in te plannen dat de toepassing en de bijbehorende service niet moeten blijven werken.
Deze tutorial gaat ervan uit dat je een basiskennis hebt van Android en Java, dat je alle Android-tools hebt geïnstalleerd en werkt en dat je vertrouwd bent met het laden en testen van applicaties op een Android-apparaat. We gebruiken de barometer-hardwaresensor in deze toepassing. Als u geen apparaat hebt met deze sensor, kunt u deze vervangen door een andere, vergelijkbare sensor voor testdoeleinden, maar de resultaten of bruikbaarheid zijn mogelijk niet hetzelfde.
De hardwaresensoren zijn toegankelijk via de SensorManager-klasse. Via een instantie van deze klasse kan een toepassing verschillende sensorobjecten opvragen die de onderliggende hardware vertegenwoordigen. Met behulp van deze kan een toepassing beginnen te luisteren naar gegevens afkomstig van de sensorhardware.
Krijg eerst een instantie van de klasse SensorManager, zoals deze:
SensorManager sensorManager = (SensorManager) getSystemService (SENSOR_SERVICE);
Voer vervolgens een query uit voor de Sensor.TYPE_PRESSURE-sensor, die de barometrische sensor is:
Sensor sensor = sensorManager.getDefaultSensor (Sensor.TYPE_PRESSURE);
Voor het gebruik van de klasse SensorManager en leessensoren zijn geen speciale machtigingen vereist.
U kunt nu registreren om gebeurtenissen van de sensor te ontvangen. Hiertoe moet u een SensorEventListener implementeren en de SensorManager-klasse erover vertellen.
Hier is bijvoorbeeld de structuur voor een implementatie van een SensorEventListener:
class MyListener implementeert SensorEventListener @Override public void onAccuracyChanged (Sensor sensor, int accuracy) // TODO @Override public void onSensorChanged (SensorEvent event) // TODO
Registreer u dan voor evenementen door SensorManager over uw luisteraar te vertellen:
sensorManager.registerListener (myListenerInstance, sensor, SensorManager.SENSOR_DELAY_NORMAL);
U kunt zich registreren om gebeurtenisupdates te ontvangen tegen verschillende tarieven. Hoe sneller de snelheid, hoe vaker de updates, maar ook hoe sneller de batterij van het apparaat leegloopt. Hier gebruiken we de standaardsnelheid. Controleer de retourwaarde van de registerListener () -aanroep om te zien of deze succesvol was of niet. Als dit waar is, is de sensor beschikbaar en is het luisteren begonnen. Als deze fout is, is de sensor mogelijk niet beschikbaar (om welke reden dan ook).
De klasse om sensorgebeurtenissen te ontvangen is generiek voor alle sensoren via de klasse SensorEvent. Als zodanig is het SensorEvent-waardeveld een array om meer gegevens te verwerken dan onze enkele numerieke barometrische sensor biedt. We zijn alleen geïnteresseerd in de eerste waarde van de array en de tijdstempel:
@Override public void onSensorChanged (SensorEvent event) long timestamp = event.timestamp; floatwaarde = event.values [0]; // doe iets met de waarden
Tot slot, om het luisteren naar de sensor te stoppen, eenvoudig de registratie ongedaan maken:
sensorManager.unregisterListener (myListenerInstance);
U dient zich alleen te registreren wanneer uw toepassing gereed is en de sensorgegevens nodig heeft en vervolgens de registratie ongedaan te maken zodra deze niet langer nodig is. Dit helpt apparaatbronnen zoals batterijvermogen verstandig te gebruiken.
Het is waarschijnlijk niet interessant om de app de hele tijd te laten draaien om sensorwaarden te controleren. Maak in plaats daarvan een Service en laat de Service regelmatig starten door een herhalend alarm via AlarmManager te gebruiken.
Een service op Android is een manier om toepassingscode te laten uitvoeren die niet is gekoppeld aan een bepaalde activiteit en waarvoor geen eigen gebruikersinterface nodig is. Net als een activiteit, wordt code in een service uitgevoerd op de hoofdthread, dus normale achtergrondverwerkingstechnieken moeten worden uitgevoerd voor langdurige bewerkingen. Een dienst kan worden gebruikt via een intentie of door te binden en methodische oproepen op afstand te doen. Het type service dat we implementeren, kan het beste worden gedaan via Intent-afhandeling.
De kern van een serviceklasse heeft twee implementatiemethoden, de methode onStartCommand () en de methode onBind (). Aangezien we geen binding hanteren, zullen we onBind () eenvoudig behandelen. Dit is de kern van onze service, inclusief de implementatie van SensorEventListener:
public class BaroLoggerService breidt service-instrumenten uit SensorEventListener private static final String DEBUG_TAG = "BaroLoggerService"; private SensorManager sensorManager = null; privé Sensor sensor = nul; @Override public int onStartCommand (Intent intent, int flags, int startId) sensorManager = (SensorManager) getSystemService (SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor (Sensor.TYPE_PRESSURE); sensorManager.registerListener (this, sensor, SensorManager.SENSOR_DELAY_NORMAL); terug START_STICKY; @Override openbare IBinder onBind (Intent opzet) return null; @Override public void onAccuracyChanged (Sensor sensor, int accuracy) // do nothing @Override public void onSensorChanged (SensorEvent event) // pak de waarden en tijdstempel // ... // stop de sensor- en servicesensorManager.unregisterListener ( deze); stopSelf ();
Het schrijven van gegevens naar schijf is een blokkerende bewerking en moet worden uitgevoerd op een achtergrondthread. Een eenvoudige manier om dit te doen is via een AsyncTask. Binnen de Service kunnen we een AsyncTask toevoegen en het SensorEvent doorgeven als volgt:
@Override public void onSensorChanged (SensorEvent event) // pak de waarden en tijdstempel - off the thread new SensorEventLoggerTask (). Execute (event); // stop de service stopZelf (); private class SensorEventLoggerTask breidt AsyncTask uit@Override beschermd Void doInBackground (SensorEvent ... events) SensorEvent event = events [0]; // log de waarde in
Een service wordt normaal gesproken gestart via de Context-methode startService (). Het volgende zou bijvoorbeeld werken vanuit een Activity-klasse:
Intent intent = new Intent (getApplicationContext (), BaroLoggerService.class); startService (intent);
Dit is echter niet wat we willen. We willen dat de Service slechts af en toe wordt uitgevoerd, zelfs als de toepassing niet actief is en zelfs als het apparaat in slaap is. Met de klasse AlarmManager kunnen we dit doen.
Met de klasse AlarmManager kunt u gebeurtenissen op een terugkerende manier plannen. Het maakt zelfs een efficiënte planning van veel verschillende evenementen mogelijk, niet alleen die van uzelf, wat een goede manier is om het gebruik van de batterij te verminderen.
Hier is de code die u in een activiteit onder een knop-handler kunt plaatsen, bijvoorbeeld om de service in te schakelen om eenmaal per uur te herhalen:
AlarmManager scheduler = (AlarmManager) getSystemService (Context.ALARM_SERVICE); Intent intent = new Intent (getApplicationContext (), BaroLoggerService.class); PendingIntent scheduledIntent = PendingIntent.getService (getApplicationContext (), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); scheduler.setInexactRepeating (AlarmManager.RTC_WAKEUP, System.currentTimeMillis (), AlarmManager.INTERVAL_HOUR, scheduledIntent);
We gebruiken de methode setInexactRepeating () met een specifiek gedefinieerd interval, INTERVAL_HOUR, om te profiteren van het feit dat het systeem meer wordt dan alleen ons werk. Daarnaast gebruiken we de RTC_WAKEUP-optie om aan te geven dat we willen dat het apparaat wordt gewekt voor dit alarm, in plaats van te wachten tot het om een andere reden wordt gewekt.
We hebben ook voor testdoeleinden een interval van één minuut gebruikt, zodat we niet meerdere uren hoefden te wachten om meerdere gegevenspunten te verzamelen.
Schakel het alarm uit met een aanroep van de methode cancel () met dezelfde intentie:
AlarmManager scheduler = (AlarmManager) getSystemService (Context.ALARM_SERVICE); Intent intent = nieuwe Intent (this, BaroLoggerService.class); PendingIntent scheduledIntent = PendingIntent.getService (getApplicationContext (), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); scheduler.cancel (scheduledIntent);
U kunt deze gesprekken op elke gewenste manier uitvoeren. We hebben een aantal knopbedieningen gemaakt die in onze activiteit methodes hebben genoemd met deze aanroepen.
In deze zelfstudie hebt u geleerd om een sensorwaarde op de achtergrond regelmatig te controleren met objecten SensorManager, Service en AlarmManager. De serie gaat door met meer informatie over het opslaan en weergeven van de gegevens.
Als een uitdaging, implementeer deze code alleen. Probeer een aantal andere sensortypen die uw apparaat ondersteunt. Ondersteunt het TYPE_AMBIENT_TEMPERATURE? TYPE_RELATIVE_HUMIDITY? TYPE_LIGHT? Zou het nuttig zijn om de locatie van de metingen te registreren? Wees creatief en vertel ons wat je verzint in de reacties!
Mobiele ontwikkelaars Lauren Darcey en Shane Conder hebben samen meerdere boeken geschreven over Android-ontwikkeling: een diepgaand programmeerboek getiteld Android Wireless Application Development (nu in zijn derde editie als set met twee volumes) en Sams Teach Yourself Android Application Development in 24 uur. Wanneer ze niet schrijven, besteden ze hun tijd aan het ontwikkelen van mobiele software bij hun bedrijf en het leveren van consultingservices. Ze zijn te bereiken via e-mail naar [email protected], via hun blog op androidbook.blogspot.com, en op Twitter @androidwireless.