Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 41 di 97
  • livello avanzato
Indice lezioni

Accelerometro: come utilizzarlo

Utilizzare l'accelerometro in un'app Android: ecco come fare.
Utilizzare l'accelerometro in un'app Android: ecco come fare.
Link copiato negli appunti

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.

Ti consigliamo anche