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

Geolocalizzazione con Android

Come richiedere informazioni al GPS del dispositivo e geolocalizzare uno smartphone o un tablet Android
Come richiedere informazioni al GPS del dispositivo e geolocalizzare uno smartphone o un tablet Android
Link copiato negli appunti

L'utente passa giornate spostandosi e raccogliendo informazioni - più o meno volutamente - nel proprio device Android. Consultazioni internet, appunti,
eventi calendario, foto, chiamate, messaggi. Il dispositivo diventa una specie di “diario errante” dell'esperienza di vita quotidiana. La possibilità di
associare informazioni geografiche a questi ricordi apre scenari nuovi e ciò basta a giustificare la rapidissima diffusione che ha avuto nell'informatica
mobile la geolocalizzazione.

Intendiamo con questo termine la capacità di un dispositivo di rilevare la propria posizione geografica nel mondo reale. Non stiamo parlando ormai di una
dote rara, quasi ogni smartphone o tablet oggi contiene dei sistemi di localizzazione.

I più comuni sono:

  • network-based: rileva le reti mobili Wi-Fi e GSM disponibili nella zona ed in base a questi calcola la propria posizione. Non molto
    accurato ma immancabile nei dispositivi;
  • GPS (Global Positioning System): acronimo famosissimo, si basa sull'intercettazione di messaggi inviati da satelliti che ruotano attorno
    alla Terra. Tali comunicazioni contengono l'informazione oraria ed altri dati relativi all'orbita percorsa. Il dispositivo intercettando i segnali di
    almeno quattro di questi satelliti con l'applicazione di formule matematiche riesce a calcolare la propria posizione. Accurato e diffusissimo tranne che in
    alcuni dispositivi di fascia bassa. Praticamente il sistema di localizzazione per antonomasia.

In questa lezione, viene trattata la localizzazione mediante un componente detto LocationManager. Tali API, nonostante svolgano correttamente il loro lavoro e siano state usate ampiamente dagli sviluppatori, non dovrebbero più essere impiegate nei nuovi progetti e, ove possibile,
sostituite in quelli esistenti. L'alternativa consigliata dalla documentazione ufficiale è costituita dai Location Services, opportunamente approfonditi nella Guida ai Servizi Google, disponibile su HTML.it. Essi offrono vantaggi in termini di prestazioni e accuratezza di misurazione, a fronte di una migliore gestione delle risorse energetiche nonchè una naturale integrazione con i servizi di Google.

Esempio pratico: GPS nell'Activity

Entriamo subito nel vivo creando un'Activity che richiede informazioni GPS e le mostra nel suo layout. Oltre a latitudine e longitudine l'Activity mediante
un oggetto denominato GeoCoder recupererà l'indirizzo cui corrisponde la posizione.

Il layout dell'activity è una griglia molto semplice. TableLayout con una serie di campi di testo da completare:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TableRow android:padding="5dp">
<TextView android:text="Abilitato" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:id="@+id/enabled" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</TableRow>
<TableRow android:padding="5dp">
<TextView android:text="Data ora" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:id="@+id/timestamp" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</TableRow>
<TableRow android:padding="5dp">
<TextView android:text="Latitudine" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:id="@+id/latitude" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</TableRow>
<TableRow android:padding="5dp">
<TextView android:text="Longitudine" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:id="@+id/longitude" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</TableRow>
<TableRow android:padding="5dp">
<TextView android:text="Località" android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:id="@+id/where" android:padding="5dp"
android:lines="2"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</TableRow>
</TableLayout>

Da ricordare che per l'accesso ai dati GPS è necessaria un'apposita permission. Nel manifest andremo ad inserire questa riga:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Questa permission va bene sia per usare il GPS sia per la localizzazione network-based. Qualora si volesse usare solo quest'ultima è sufficiente la
permission ACCESS_COARSE_LOCATION.

All'interno dell'Activity dovremo per prima cosa registrare un Listener presso il LocationManager e lo faremo nel metodo onResume. Tale istanza sarà
annullata in onPause.

public class MainActivity extends Activity
{
private String providerId = LocationManager.GPS_PROVIDER;
private Geocoder geo = null;
private LocationManager locationManager=null;
private static final int MIN_DIST=20;
private static final int MIN_PERIOD=30000;
private LocationListener locationListener = new LocationListener()
{
. . .
. . .
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume()
{
super.onResume();
geo=new Geocoder(this, Locale.getDefault());
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location!=null)
updateGUI(location);
if (locationManager!=null && locationManager.isProviderEnabled(providerId))
updateText(R.id.enabled, "TRUE");
else
updateText(R.id.enabled, "FALSE");
locationManager.requestLocationUpdates(providerId, MIN_PERIOD,MIN_DIST, locationListener);
}
@Override
protected void onPause()
{
super.onPause();
if (locationManager!=null && locationManager.isProviderEnabled(providerId))
locationManager.removeUpdates(locationListener);
}
. . .
. . .
}

Notare che, nell'onResume, il metodo requestLocationUpdates effettua la vera registrazione del listener. I parametri che utilizza sono:

  • l'id del provider: la costante stringa che individua il tipo di provider da usare;
  • il minimo intervallo di tempo, in millisecondi, che deve trascorrere tra aggiornamenti della posizione;
  • la minima distanza in metri che deve intercorrere tra due misurazioni;
  • l'oggetto che svolge il ruolo di listener. Lo vedremo subito.

L'oggetto listener registrato viene implementato come classe interna all'Activity:

private LocationListener locationListener = new LocationListener()
{
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
@Override
public void onProviderEnabled(String provider)
{
// attivo GPS su dispositivo
updateText(R.id.enabled, "TRUE");
}
@Override
public void onProviderDisabled(String provider)
{
// disattivo GPS su dispositivo
updateText(R.id.enabled, "FALSE");
}
@Override
public void onLocationChanged(Location location)
{
updateGUI(location);
}
};

I primi tre metodi – onStatusChanged, onProviderEnabled, onProviderDisabled – notificano, rispettivamente, se il provider è disponibile o meno, se è
abilitato, se è stato disabilitato.

L'ultimo metodo onLocationChanged è il cuore del listener e viene invocato ogni volta che nuove
informazioni di posizione sono state recapitate.

L'oggetto Location contiene tutto ciò che è stato appreso dall'ultima misurazione del posizionamento e viene inviata al metodo updateGUI per riflettere gli
aggiornamenti sulla interfaccia utente:

private void updateGUI(Location location)
{
Date timestamp = new Date(location.getTime());
updateText(R.id.timestamp, timestamp.toString());
double latitude = location.getLatitude();
updateText(R.id.latitude, String.valueOf(latitude));
double longitude = location.getLongitude();
updateText(R.id.longitude, String.valueOf(longitude));
new AddressSolver().execute(location);
}
private void updateText(int id, String text)
{
TextView textView = (TextView) findViewById(id);
textView.setText(text);
}

All'interno di updateGUI, oltre al codice di modifica delle TextView, è presente l'invocazione al Geocoder per la conversione delle
coordinate in un indirizzo vero e proprio. Il Geocoder viene consultato in maniera asincrona mediante AsyncTask. Nel metodo doInBackground, la Location
sarà convertita in una stringa frutto della concatenazione delle informazioni reperite:

private class AddressSolver extends AsyncTask<Location, Void, String>
{
@Override
protected String doInBackground(Location... params)
{
Location pos=params[0];
double latitude = pos.getLatitude();
double longitude = pos.getLongitude();
List<Address> addresses = null;
try
{
addresses = geo.getFromLocation(latitude, longitude, 1);
}
catch (IOException e)
{
}
if (addresses!=null)
{
if (addresses.isEmpty())
{
return null;
}
else {
if (addresses.size() > 0)
{
StringBuffer address=new StringBuffer();
Address tmp=addresses.get(0);
for (int y=0;y<tmp.getMaxAddressLineIndex();y++)
address.append(tmp.getAddressLine(y)+"\n");
return address.toString();
}
}
}
return null;
}
@Override
protected void onPostExecute(String result)
{
if (result!=null)
updateText(R.id.where, result);
else
updateText(R.id.where, "N.A.");
}
}

Ti consigliamo anche