Android e la gestione dei sensori
Come sappiamo, Android gira solo ed esclusivamente su questi tipi di dispositivi che sono tecnologicamente molto avanzati. Quindi ovviamente la piattaforma è predisposta - attraverso un set di librerie - all'utilizzo di questi componenti integrati. La cosa sorprendente è la facilità con cui ci permette di accedere ai sensori e manipolari i dati, oppure verificare quali tipi di sensori possiede un determinato dispositivo.
Sensor e SensorManager
La classe che si occupa della gestione dei sensori è android.hardware.SensorManager di cui si può ottenere un'istanza attraverso il metodo getSystemService() della classe Context (superclasse dell'Activity). Il metodo riceve come parametro un intero che rappresenta appunto l'identificativo del tipo di servizio a cui vogliamo accedere. Nel nostro caso l'identificativo è rappresentato dalla costante statica Context.SENSOR_SERVICE. Vediamo come ottenere un riferimento del SensorManager all'interno di un'Activity:SensorManager manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);Un sensore invece è rappresentato da una particolare istanza della classe android.hardware.Sensor. La classe Sensor implementa i seguenti metodi:
- public float getMaximumRange():portata massima del sensore
- public String getName():il nome del sensore
- public float getPower():la potenza in mA utilizzati da questo sensore durante l'uso
- public float getResolution():risoluzione del sensore:
- public int getType():ritorna un intero che identifica la tipologia di sensori a cui è associato.
- public int getVersion(): versione del modulo sensore
public List<Sensor> getSensorList(int n)L'intero che riceve il metodo come parametro identifica il tipo di sensore, definite nella classe Sensor da alcune costanti statiche. Vediamole:
- TYPE_ACCELEROMETER: sensore accelerometro
- TYPE_GYROSCOPE: sensore giroscopio
- TYPE_LIGHT: sensore per la luce
- TYPE_MAGNETIC_FIELD: sensore magnetico
- TYPE_ORIENTATION: deprecata.Si deve utilizzare invece il metodo SensorManager.getOrientation()
- TYPE_PRESSURE: sensore di pressione
- TYPE_PROXIMITY: sensore di prossimità
- TYPE_TEMPERATURE: sensore di temperatura
- TYPE_ALL: tutti i tipi di sensori
List<Sensor> list = manager.getSensorList(Sensor.TYPE_ALL);
SensorEventListener
Adesso bisogna accedere ai dati che i sensori rilevano. L'approcio è asincrono, cioè ci registriamo attraverso un listener ed in base ha un delay impostato da noi ci vengono notificati i valori che il sensore rileva. Per prima cosa dobbiamo implementare il listener opportuno che viene rappresentato dall'interfaccia SensorEventListener che definisce i seguenti metodi:- void onAccuracyChanged(Sensor sensor, int accurancy): viene invocato quando la precisione del sensore è cambiata
- void onSensorChanged(SensorEvent event): viene invocato quando i valori del sensore sono cambiati
class MySensorListener implements SensorEventListener { public void onAccuracyChanged(Sensor sensor, int accurancy) { ... } public void onSensorChanged(SensorEvent event) { ... } }I valori generati dal sensore vengono incapsulati nella classe SensorEvent che non contiene metodi ma semplicemente membri ad accesso public:
- public int accuracy: valore che indica l'accuratezza del segnale
- public Sensor sensor: riferimento all'oggetto Sensor che ha generato l'evento
- public long timestamp: il timestamp in nanosecondi
- public final float[] values: i valori veri e propri del segnale acquisito dal sensore. Ad esempio con un accelerometro questi valori sono da intendersi in m/s^2
public void onSensorChanged(SensorEvent event) { float [] f = event.values; for(int i = 0; i < f.length; i++) Log.i("Valore "+i+" :",""+f[i]);//Metodo simile al System.out.println, che in questo caso //genera un log nella finestra LogCat dell'ADT }
Registrare il listener
Per registrare il listener si usa il SensorManager che implementa i metodi sia per la regsitrazione che per la disinstallazione del listener. Ad esempio immagianiamo di avere un accelerometro installato sul nostro dispositivo, vediamo come rilevarlo ed installare il listener:List<Sensor> list = manager.getSensorList(Sensor.TYPE_ACCELEROMETER); Sensor s = list.get(0); manager.registerListener(new MySensorListener(), s, SensorManager.SENSOR_DELAY_NORMAL);La costante SensorManager.SENSOR_DELAY_NORMAL indica la frequenza con cui ci vengono aggiornati i dati e questo rappresenta un livello normale. Abbiamo altri livelli di frequenza come SensorManager.SENSOR_DELAY_FAST che indica una frequenza altissima, mentre SensorManager.SENSOR_DELAY_UI e SensorManager.SENSOR_DELAY_GAME adtte per l'interfaccia grafica e per i giochi.
Esempio di un'applicazione con i sensori
Per concludere vediamo un esempio di un'applicazione che rileva tutti i tipi di sensori che sono presenti nel dispositivo. Per ogni sensore rilevato installa un listener e visualizza sul display (attraverso delle TextView) il nome ed i valori rilevati da ciascun sensore. Per quanto riguarda l'interfaccia grafica in questo caso è stata implementata senza ricorrere al layout definito in XML ma semplicemnte creando l'interfaccia grafica direttamente da codice. Quindi create un nuovo progetto e definite il nome dell'activity TestSensor, poi basta copiare ed incollare il codice di questa classe all'interno dell'activity:import java.util.List; import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.util.Log; import android.widget.TableLayout; import android.widget.TextView; public class TestSensor extends Activity { private TableLayout layout; private SensorManager manager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); layout = new TableLayout(this); setContentView(layout); manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); List<Sensor> list = manager.getSensorList(Sensor.TYPE_ALL); for (Sensor s : list) { TextView[] v = installBoxSensor(s); installListenerSensor(s, v); } } private TextView[] installBoxSensor(Sensor s) { TextView view = new TextView(this); view.setText(s.getName()); layout.addView(view); TextView[] values = new TextView[3]; for (int i = 0; i < values.length; i++) { values[i] = new TextView(this); layout.addView(values[i]); } return values; } //Installazione del listener private void installListenerSensor(Sensor s, TextView[] view) { manager.registerListener(new MySensorListener(view), s, SensorManager.SENSOR_DELAY_NORMAL); } //Implementazione del listener private class MySensorListener implements SensorEventListener { private TextView value[]; public MySensorListener(TextView value[]) { this.value = value; } @Override public void onAccuracyChanged(Sensor arg0, int arg1) {} @Override public void onSensorChanged(SensorEvent arg0) { float[] values = arg0.values; value[0].setText("X: " + values[SensorManager.DATA_X]); value[1].setText("Y: " + values[SensorManager.DATA_Y]); value[2].setText("Z: " + values[SensorManager.DATA_Z]); } } }L'immagine qui sotto è lo screenshot dell'applicazione in esecuzione su un'HTC Magic:
Le applicazioni che si possono sviluppare attraverso l'utilizzo dei sensori sono molteplici. Vanno dai giochi come ad esempio Labyrinth Lite oppure strumenti di utilità come la bussola o il famoso Metal Detector che fanno uso del sensore magnetico. Quindi tutto ciò naturalmente implica una certa conoscenza di nozioni matematiche e fisiche per poter elaborare in maniera corretta questi dati.
2 Commenti per "Android e la gestione dei sensori"
Autore: moment
Ottimo articolo, complimenti e grazie per la condivisione! probabilmente la riga: TableLayout layout = new TableLayout(this); dichiarata nell'onCreate dovrebbe essere: layout = new TableLayout(this); per non creare una nuova istanza (che rimarrebbe visibile solo nell'oncreate) ed utilizzare quella dichiarata a livello di classe,altrimenti la funzione installBoxSensor() genera null pointer exception
mercoledì 20 aprile 2011 ore 22:20
Autore: Antonio Coschignano
Grazie Moment, per la segnalazione. Ho corretto la riga..
lunedì 30 maggio 2011 ore 17:40
Lascia un commento
Tutti i commenti inseriti devono essere approvati da un amministratore prima di essere visualizzati al pubblico. Si tratta di una misura preventiva contro spam e pubblicità e non è necessario reinviare il commento. Si prega di scrivere commenti in tema. Spam e messaggi promozionali non vengono approvati.