Les smartphones regorgent de capteurs matériels, tels que des accéléromètres, des capteurs de lumière, des gyroscopes, etc. Apprenez à recueillir des données à partir de ces capteurs en mettant en œuvre un enregistreur barométrique..
Dans la suite du dernier tutoriel, Picking App Components, nous allons cette fois implémenter un code permettant de lire régulièrement les données du capteur barométrique. Vous apprendrez à lire les données du capteur et à planifier des événements récurrents de manière à ce que l'application et son service ne restent pas en cours d'exécution..
Ce didacticiel suppose que vous maîtrisiez bien Android et Java, que tous les outils Android étaient installés et fonctionnaient et que vous maîtrisiez bien le chargement et le test d'applications sur un appareil Android. Nous utiliserons le capteur matériel du baromètre dans cette application. Si vous n'avez pas d'appareil avec ce capteur, vous pouvez le remplacer par un autre capteur similaire à des fins de test, mais les résultats ou l'utilité peuvent ne pas être équivalents.
Les capteurs matériels sont accessibles via la classe SensorManager. Grâce à une instance de cette classe, une application peut interroger différents objets Sensor représentant le matériel sous-jacent. Grâce à ceux-ci, une application peut alors commencer à écouter les données provenant du matériel du capteur..
Commencez par obtenir une instance de la classe SensorManager, comme suit:
SensorManager sensorManager = (SensorManager) getSystemService (SENSOR_SERVICE);
Ensuite, recherchez le capteur Sensor.TYPE_PRESSURE, qui est le capteur barométrique:
Capteur capteur = sensorManager.getDefaultSensor (Sensor.TYPE_PRESSURE);
L'utilisation de la classe SensorManager et des capteurs de lecture ne nécessite aucune autorisation spéciale..
Vous pouvez maintenant vous inscrire pour recevoir les événements du capteur. Pour ce faire, vous devez implémenter un SensorEventListener et en informer la classe SensorManager..
Par exemple, voici la structure pour une implémentation d'un SensorEventListener:
La classe MyListener implémente SensorEventListener @Override public void onAccuracyChanged (capteur, précision int) // TODO @Override public void onSensorChanged (événement SensorEvent) // TODO
Puis inscrivez-vous aux événements en informant SensorManager de votre auditeur:
sensorManager.registerListener (myListenerInstance, capteur, SensorManager.SENSOR_DELAY_NORMAL);
Vous pouvez vous inscrire pour recevoir des mises à jour d'événements à différents taux. Plus le débit est rapide, plus les mises à jour sont fréquentes, mais plus la batterie de l'appareil s'épuise rapidement. Ici, nous utilisons le taux par défaut. Vérifiez la valeur de retour de l'appel registerListener () pour voir s'il a réussi ou non. Si true, le capteur est disponible et l'écoute a commencé. Si faux, le capteur peut ne pas être disponible (pour une raison quelconque).
La classe destinée à recevoir des événements de capteur est générique pour tous les capteurs via la classe SensorEvent. En tant que tel, le champ de valeur SensorEvent est un tableau permettant de traiter plus de données que ne le fournit notre capteur barométrique numérique. Nous ne nous intéressons qu'à la première valeur du tableau et à l'horodatage:
@Override public void onSensorChanged (événement SensorEvent) long timestamp = event.timestamp; valeur float = event.values [0]; // faire quelque chose avec les valeurs
Enfin, pour arrêter d'écouter le capteur, annulez simplement son enregistrement:
sensorManager.unregisterListener (myListenerInstance);
Vous ne devez vous enregistrer que lorsque votre application est prête et a besoin des données du capteur, puis vous désinscrire dès que vous n'en avez plus besoin. Cela permet d’utiliser judicieusement les ressources du périphérique, telles que l’alimentation par batterie.
Vous n'êtes probablement pas intéressé à laisser l'application en cours d'exécution tout le temps pour vérifier les valeurs des capteurs. Au lieu de cela, créez un service et faites-le démarrer régulièrement à l'aide d'une alarme répétée via AlarmManager..
Un service sur Android est un moyen d'exécuter du code d'application qui n'est pas lié à une activité particulière et qui ne nécessite aucune interface utilisateur. À l'instar d'une activité, le code d'un service s'exécute sur le thread principal. Par conséquent, les techniques de traitement en arrière-plan normales doivent être exécutées pour les opérations longues. Un service peut être utilisé via une intention ou en liant et en effectuant des appels de méthode à distance. Le type de service que nous mettons en œuvre est mieux réalisé via la gestion des intentions..
Le noyau d'une classe de service doit implémenter deux méthodes, la méthode onStartCommand () et la méthode onBind (). Puisque nous ne gérons pas la liaison, nous allons simplement gérer onBind (). Voici le cœur de notre service, y compris l’implémentation de SensorEventListener:
Classe publique BaroLoggerService extended Le service implémente SensorEventListener private static final String DEBUG_TAG = "BaroLoggerService"; private SensorManager sensorManager = null; capteur privé = nul; @Override public int onStartCommand (Intentive, Int flags, Int startId) sensorManager = (SensorManager) getSystemService (SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor (Sensor.TYPE_PRESSURE); sensorManager.registerListener (this, sensor, SensorManager.SENSOR_DELAY_NORMAL); renvoie START_STICKY; @Override public IBinder onBind (Intentive) return null; @Override public nul onAccuracyChanged (capteur, exactitude) // ne fait rien @Override public nul onSensorChanged (événement SensorEvent) // récupère les valeurs et l'horodatage //… // arrête le capteur et le service sensorManager.unregisterListener ( ce); stopSelf ();
L'écriture de données sur le disque est une opération bloquante et doit être effectuée sur un thread d'arrière-plan. Une méthode simple consiste à effectuer une tâche asynchrone. Dans le Service, nous pouvons ajouter une AsyncTask et lui transmettre le SensorEvent pour le gérer comme suit:
@Override public void onSensorChanged (événement SensorEvent) // récupère les valeurs et l'horodatage - désactive le nouveau thread principal SensorEventLoggerTask (). Execute (event); // arrête le service stopSelf (); la classe privée SensorEventLoggerTask étend AsyncTask@Override protected Void doInBackground (événements SensorEvent…) événement SensorEvent = événements [0]; // enregistre la valeur
Un service est normalement démarré via la méthode contextuelle startService (). Par exemple, ce qui suit pourrait fonctionner à partir d'une classe d'activité:
Intention Intent = new Intent (getApplicationContext (), BaroLoggerService.class); startService (intention);
Ce n'est pas ce que nous voulons cependant. Nous voulons que le service ne s'exécute qu'occasionnellement, même si l'application ne s'exécute pas et même si l'appareil est en veille. La classe AlarmManager nous permet de le faire.
La classe AlarmManager vous permet de planifier des événements de manière récurrente. Il permet même de planifier efficacement de nombreux événements différents, pas seulement le vôtre, ce qui est un bon moyen de réduire l'utilisation de la batterie..
Voici le code, que vous pouvez placer dans une activité sous un gestionnaire de boutons, par exemple, pour activer le service à répéter une fois par heure:
Planificateur AlarmManager = (AlarmManager) getSystemService (Context.ALARM_SERVICE); Intention Intent = new Intent (getApplicationContext (), BaroLoggerService.class); PendingIntent scheduleIntent = PendingIntent.getService (getApplicationContext (), 0, intention, PendingIntent.FLAG_UPDATE_CURRENT); scheduler.setInexactRepeating (AlarmManager.RTC_WAKEUP, System.currentTimeMillis (), AlarmManager.INTERVAL_HOUR, scheduleIntent);
Nous utilisons la méthode setInexactRepeating () avec un intervalle spécifiquement défini, INTERVAL_HOUR, pour tirer parti du système qui se réveille pour bien plus que notre travail. De plus, nous utilisons l'option RTC_WAKEUP pour indiquer que nous voulons que le périphérique soit réveillé pour cette alarme, plutôt que d'attendre qu'il se réveille pour une autre raison..
De plus, à des fins de test, nous avons utilisé un intervalle d'une minute afin que nous n'ayons pas à attendre plusieurs heures pour collecter plusieurs points de données..
Désactivez l'alarme en appelant la méthode cancel () avec la même intention:
Planificateur AlarmManager = (AlarmManager) getSystemService (Context.ALARM_SERVICE); Intention d'intention = nouvelle intention (this, BaroLoggerService.class); PendingIntent scheduleIntent = PendingIntent.getService (getApplicationContext (), 0, intention, PendingIntent.FLAG_UPDATE_CURRENT); scheduler.cancel (scheduleIntent);
Vous pouvez effectuer ces appels comme bon vous semble. Nous avons créé quelques contrôles de bouton qui ont appelé des méthodes dans notre activité avec ces appels..
Dans ce didacticiel, vous avez appris à vérifier régulièrement une valeur de capteur en arrière-plan à l'aide d'objets SensorManager, Service et AlarmManager. La série continuera avec plus d'informations sur le stockage et l'affichage des données.
Comme défi, implémentez ce code vous-même. Essayez d'autres types de capteurs pris en charge par votre appareil. Prend-il en charge TYPE_AMBIENT_TEMPERATURE? TYPE_RELATIVE_HUMIDITY? TYPE_LIGHT? Serait-il utile de noter l'emplacement des mesures? Soyez créatif et dites-nous ce que vous proposez dans les commentaires!
Les développeurs mobiles Lauren Darcey et Shane Conder ont co-écrit plusieurs livres sur le développement Android: un livre de programmation en profondeur intitulé Développement d'applications sans fil Android (maintenant dans sa troisième édition en deux volumes) et Sams Teach Yourself Développement d'applications Android en 24 heures. Lorsqu'ils n'écrivent pas, ils passent leur temps à développer des logiciels mobiles dans leur entreprise et à fournir des services de conseil. Vous pouvez les contacter par courrier électronique à l'adresse [email protected], via leur blog à l'adresse androidbook.blogspot.com et sur Twitter @androidwireless..