Accelerometro: come utilizzarlo

10 settembre 2014

Uno dei sensori più ampiamente diffusi nei dispositivi Android è di sicuro l’accelerometro. Quindi, con riguardo alla sua ampia diffusione ed importanza, in questo capitolo sarà oggetto di un esempio che per quanto semplice potrà apparire dotato di una certa valenza pratica.

Esempio: usare lo “shake”

In questo esempio vedremo come intercettare un evento di shake e collegarvi una reazione. Per shake intendiamo genericamente l’atto di scuotere il dispositivo indipendentemente dalla direzione. Le accelerazioni fisiche impresse sull’hardware vengono captate dall’accelerometro. Il nostro compito sarà quello di capire se la loro intensità complessiva è tale da potervi riconoscere l’avvenimento di uno shake. Solo in questo caso attiveremo la reazione.

Nell’esempio, il layout è costituito da un solo form. Se durante la compilazione viene effettuato uno shake, il dispositivo chiederà a mezzo finestra di dialogo se si vuole procedere alla cancellazione dei valori inseriti nei campi.

Il codice del layout, come presumibile, non offre grandi novità. Questo il contenuto del file res/layout/activity_main.xml:

    <TableLayout  xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
    	android:layout_height="match_parent">
       <TableRow >
           <TextView android:layout_weight="1"
    				 android:layout_height="wrap_content" android:text="Username:"
    				 android:id="@+id/label1"/>
           <EditText android:layout_weight="5"
               		 android:inputType="text"
    				 android:layout_height="wrap_content" 
    				 android:id="@+id/text1"/>
       </TableRow>
       <TableRow >
           <TextView android:layout_weight="1"
    				 android:layout_height="wrap_content" android:text="Password:"
    				 android:id="@+id/label2"/>
           <EditText android:layout_weight="5"
               		 android:inputType="textPassword"
    				 android:layout_height="wrap_content" android:id="@+id/text2"/>
       </TableRow>
       <TableRow >
           <Button  android:id="@+id/button1"
               		android:layout_width="wrap_content"
    				 android:layout_height="wrap_content"
    				 android:text="Salva"/>
           <Button android:layout_width="wrap_content"
    				 android:layout_height="wrap_content"
    				 android:text="Annulla"
    				 android:id="@+id/button2"/>
       </TableRow>
    </TableLayout>

“Ascoltare” il sensore

L’Activity dovrà svolgere il ruolo di listener per eventi del sensore:

public class MainActivity extends Activity implements SensorEventListener
{
	private SensorManager mSensorManager;
	private Sensor mAccelerometer;
	private float lastAcc = 0.0f;
	private float acceleration = 0.0f;
	private float totAcc = 0.0f;
	private boolean onEvent = false;
	
	. . .
	. . .
	
} // fine MainActivity

I membri privati contengono, in primis, riferimenti al SensorManager e ad un Sensor che in questo caso è l’accelerometro. Le altre variabili di tipo float serviranno per custodire valori temporanei nel calcolo delle accelerazioni.

Il metodo onCreate svolge le inizializzazioni assegnando il valore opportuno ai membri privati. Notiamo che le variabili float delle accelerazioni verranno impostate a valori corrispondenti alla gravità terrestre.

	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
		mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		lastAcc=SensorManager.GRAVITY_EARTH;
		acceleration=SensorManager.GRAVITY_EARTH;
	}

Nel capitolo riguardante il ciclo di vita delle Activity si è spiegato a cosa servono i metodi onResume e onPause: segnano, rispettivamente, l’inizio e la fine dell’interazione tra interfaccia e utente. Visto che la nostra Activity dovrà registrarsi per ricevere prontamente segnalazioni sugli eventi dell’accelerometro, per evitare di impiegare inutilmente risorse rinnoverà tale registrazione all’interno dell’onResume e la disdirà ad ogni onPause. Al di fuori dell’intervallo di tempo segnato da questi metodi, sarebbe assolutamente inutile oltre che vanamente dispendioso richiedere segnalazioni in merito.

protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
    }

    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
    }

L’implementazione dell’interfaccia SensorEventListener richiede l’override di due metodi:

  • onAccuracyChanged: chiamato quando l’accuratezza del sensore viene modificata. Nell’esempio non riceverà un’implementazione;
  • onSensorChanged: come già appreso alcuni capitoli fa, riceve notifiche sugli eventi del sensore incarnati da un oggetto SensorEvent. Qui verrà inserito tutto il codice di gestione dell’evento e proprio dal SensorEvent leggeremo le accelerazioni ricevute.
	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) 
	{ 	}
	
	@Override
	public void onSensorChanged(SensorEvent event) 
	{
		if (!onEvent)
		{
			float x = event.values[0];
			float y = event.values[1];
			float z = event.values[2];
		
			lastAcc = acceleration;
			acceleration = x*x+y*y+z*z;
			float diff = acceleration - lastAcc;
			totAcc = diff*acceleration;
			if (totAcc>15000)
			{
				onEvent=true;
				AlertDialog.Builder builder=new Builder(this);
				builder.setMessage("Pulire il form?");
				builder.setPositiveButton("Sì", new OnClickListener() 
				{
					@Override
					public void onClick(DialogInterface arg0, int arg1)
					{
						clean();
						onEvent = false;
					
					}
				});
				builder.setNegativeButton("No",  new OnClickListener() 
				{
					@Override
					public void onClick(DialogInterface arg0, int arg1)
					{
						onEvent=false;
					
					}
				});
				builder.show();
			}
		}
		  
	}
	
	private void clean()
	{
		TextView txt1=(TextView) findViewById(R.id.text1);
		TextView txt2=(TextView) findViewById(R.id.text2);
		txt1.setText("");
		txt2.setText("");
	}

L’ulteriore metodo visibile nel codice, clean, verrà invocato quando si riterrà opportuno cancellare il form.

Tutto il riconoscimento dello shake si trova in queste righe:

float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
		
lastAcc = acceleration;
acceleration = x*x+y*y+z*z;
float diff = acceleration - lastAcc;
totAcc = diff*acceleration;
if (totAcc>15000)
{

Da event verranno lette le tre accelerazioni (una per ogni dimensione dello spazio). La risultante verrà calcolata sommandone i quadrati. La variabile lastAcc serve a salvare l’ultimo valore calcolato – quello che è avvenuto con l’evento precedente – mentre acceleration conterrà il nuovo valore. Infine in totAcc si cercherà di valutare l’entità della variazione. Se tale valore supera la soglia di 15000 assumeremo che lo shake sia avvenuto.

Il codice contenuto nel blocco if quindi sarà la vera reazione allo shake. L’Activity dovrà sapere sempre che il trattamento dell’evento è in corso. Glielo dirà il valore di onEvent che verrà impostato a true non appena la variazione delle accelerazioni raggiungerà 15000.

Gli eventi dell’accelerometro verranno invocati molto spesso quindi dovremo stare attenti ad eseguire meno codice possibile e solo nei casi in cui sia strettamente necessario. Se si nota, non appena viene invocato onSensorChanged si verifica se è in corso la gestione di uno shake con:

if (!onEvent)

In caso positivo nulla sarà fatto per il momento. Ovviamente è fondamentale resettare onEvent impostandolo di nuovo a false nel momento in cui la finestra di dialogo viene chiusa.

Tutte le lezioni

1 ... 39 40 41 ... 82

Se vuoi aggiornamenti su Accelerometro: come utilizzarlo inserisci la tua e-mail nel box qui sotto:
Tags:
 
X
Se vuoi aggiornamenti su Accelerometro: come utilizzarlo

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy